diff --git a/.travis.yml b/.travis.yml index 9d12f0a2..4d386611 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,47 +1,37 @@ language: rust sudo: required rust: -- beta -- nightly -- stable + - beta + - nightly + - stable os: -- linux -- osx + - linux + - osx +env: + matrix: + - CI_BUILD_FEATURES="bundled" + - CI_BUILD_FEATURES="gfx image ttf mixer" + global: + - RUST_TEST_THREADS=1 + - TRAVIS_CARGO_NIGHTLY_FEATURE="" + - LD_LIBRARY_PATH: "/usr/local/lib" + - secure: MJhmVnQ2IM7+sVmc3vU4ndKOcQgLLeHUPW3qaQBQHKQmvoswCwQK60N17uSgWn1Ln8teqvSRHq4KclIjdMHI+VuQXJHQKHDgjcYbHxwmc3AM1Whnp0XB44ksKUmD109BGWSfZQxzF+6dA+YNOQ+mti+bpydMu8n2FMVjA/SXwQ8= + install: -- wget https://www.libsdl.org/release/SDL2-2.0.8.tar.gz -O sdl2.tar.gz -- tar xzf sdl2.tar.gz -- pushd SDL2-* && ./configure && make && sudo make install && popd -- wget -q https://www.libsdl.org/projects/SDL_ttf/release/SDL2_ttf-2.0.14.tar.gz -- wget -q https://www.libsdl.org/projects/SDL_image/release/SDL2_image-2.0.1.tar.gz -- wget -q https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-2.0.1.tar.gz -- wget -q -O SDL2_gfx-1.0.1.tar.gz https://sourceforge.net/projects/sdl2gfx/files/SDL2_gfx-1.0.1.tar.gz/download -- tar xzf SDL2_ttf-*.tar.gz -- tar xzf SDL2_image-*.tar.gz -- tar xzf SDL2_mixer-*.tar.gz -- tar xzf SDL2_gfx-*.tar.gz -- pushd SDL2_ttf-* && ./configure && make && sudo make install && popd -- pushd SDL2_image-* && ./configure && make && sudo make install && popd -- pushd SDL2_mixer-* && ./configure && make && sudo make install && popd -- pushd SDL2_gfx-* && ./autogen.sh && ./configure && make && sudo make install && popd + - if [[ $CI_BUILD_FEATURES != *"bundled"* ]]; then bash scripts/travis-install-sdl2.sh; fi before_script: -- shopt -s expand_aliases -- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then alias pip=pip2; fi -- | - pip install 'travis-cargo<0.2' --user && - export PATH=$HOME/.local/bin:$PATH && - export PATH=~/Library/Python/2.7/bin:$PATH + - shopt -s expand_aliases + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then alias pip=pip2; fi + - | + pip install 'travis-cargo<0.2' --user && + export PATH=$HOME/.local/bin:$PATH && + export PATH=~/Library/Python/2.7/bin:$PATH script: -- | - travis-cargo build -- --features "gfx image ttf mixer" && - travis-cargo build -- --examples --features "gfx image ttf mixer" && - travis-cargo test -- --features "gfx image ttf mixer" && - travis-cargo --only stable doc -- --features "gfx image ttf mixer" + - | + travis-cargo build -- --features "${CI_BUILD_FEATURES}" && + travis-cargo build -- --examples --features "${CI_BUILD_FEATURES}" && + travis-cargo test -- --features "${CI_BUILD_FEATURES}" && + travis-cargo --only stable doc -- --features "${CI_BUILD_FEATURES}" after_success: -- travis-cargo --only stable doc-upload -env: - global: - - RUST_TEST_THREADS=1 - - TRAVIS_CARGO_NIGHTLY_FEATURE="" - - LD_LIBRARY_PATH: "/usr/local/lib" - - secure: MJhmVnQ2IM7+sVmc3vU4ndKOcQgLLeHUPW3qaQBQHKQmvoswCwQK60N17uSgWn1Ln8teqvSRHq4KclIjdMHI+VuQXJHQKHDgjcYbHxwmc3AM1Whnp0XB44ksKUmD109BGWSfZQxzF+6dA+YNOQ+mti+bpydMu8n2FMVjA/SXwQ8= + - travis-cargo --only stable doc-upload diff --git a/Cargo.toml b/Cargo.toml index 0418964a..727b6b4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,11 +4,11 @@ name = "sdl2" description = "SDL2 bindings for Rust" repository = "https://github.com/Rust-SDL2/rust-sdl2" documentation = "https://rust-sdl2.github.io/rust-sdl2/sdl2/" -version = "0.31.0" +version = "0.32.0-beta.2" license = "MIT" authors = [ "Tony Aldridge ", "Cobrand "] -keywords = ["SDL", "windowing", "graphics", "api"] -categories = ["rendering","games","api-bindings","game-engines","multimedia"] +keywords = ["SDL", "windowing", "graphics", "api", "engine"] +categories = ["rendering","api-bindings","game-engines","multimedia"] [lib] @@ -17,9 +17,9 @@ path = "src/sdl2/lib.rs" [dependencies] bitflags = "0.7" -libc = "0.2" -rand = "0.3" -lazy_static="0.2" +libc = "^0.2" +rand = "^0.5" +lazy_static = "^1" [dependencies.num] version = "0.1" @@ -27,7 +27,7 @@ default-features = false [dependencies.sdl2-sys] path = "sdl2-sys" -version = "0.31.0" +version = "0.32.1" [dependencies.c_vec] version = ">= 1.0, <= 1.3" diff --git a/README.md b/README.md index 4e7c8126..8a7ad58f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Bindings for SDL2 in Rust -### [Changelog for 0.31](changelog.md#v031) +### [Changelog for 0.32](changelog.md#v032) # Overview @@ -257,7 +257,7 @@ download through Crates.io: ```toml [dependencies] - sdl2 = "0.31" + sdl2 = "0.32" ``` Alternatively, pull it from GitHub to obtain the latest version from master @@ -278,7 +278,7 @@ adding this instead: ```toml [dependencies.sdl2] - version = "0.31" + version = "0.32" default-features = false features = ["ttf","image","gfx","mixer"] ``` @@ -459,6 +459,58 @@ fn main() { This method is useful when you don't care about sdl2's render capabilities, but you do care about its audio, controller and other neat features that sdl2 has. +# Vulkan + +To use Vulkan, you need a Vulkan library for Rust. This example uses the +[Vulkano](https://github.com/vulkano-rs/vulkano) library. Other libraries may use different data +types for raw Vulkan object handles. The procedure to interface SDL2's Vulkan functions with these +will be different for each one. + +```rust +extern crate sdl2; +extern crate vulkano; + +use sdl2::event::Event; +use sdl2::keyboard::Keycode; +use std::ffi::CString; +use vulkano::VulkanObject; +use vulkano::instance::{Instance, RawInstanceExtensions}; +use vulkano::swapchain::Surface; + +fn main() { + let sdl_context = sdl2::init().unwrap(); + let video_subsystem = sdl_context.video().unwrap(); + + let window = video_subsystem.window("Window", 800, 600) + .vulkan() + .build() + .unwrap(); + + let instance_extensions = window.vulkan_instance_extensions().unwrap(); + let raw_instance_extensions = RawInstanceExtensions::new(instance_extensions.iter().map( + |&v| CString::new(v).unwrap() + )); + let instance = Instance::new(None, raw_instance_extensions, None).unwrap(); + let surface_handle = window.vulkan_create_surface(instance.internal_object()).unwrap(); + let surface = unsafe { Surface::from_raw_surface(instance, surface_handle, window.context()) }; + + let mut event_pump = sdl_context.event_pump().unwrap(); + + 'running: loop { + for event in event_pump.poll_iter() { + match event { + Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => { + break 'running + }, + _ => {} + } + } + ::std::thread::sleep(::std::time::Duration::new(0, 1_000_000_000u32 / 60)); + } +} + +``` + # When things go wrong Rust, and Rust-SDL2, are both still heavily in development, and you may run into teething issues when using this. Before panicking, check that you're using diff --git a/changelog.md b/changelog.md index f96fe3c9..05f9315c 100644 --- a/changelog.md +++ b/changelog.md @@ -1,16 +1,47 @@ In this file will be listed the changes, especially the breaking ones that one should be careful of when upgrading from a version of rust-sdl2 to another. -### v0.31.1 +### v0.32 -[PR #737](https://github.com/Rust-SDL2/rust-sdl2/pull/737) -* Fix `ClipboardUtil::set_clipboard_text` to return an Ok when it went well. +[PR #790](https://github.com/Rust-SDL2/rust-sdl2/pull/790): Added missing `window_id` field to `Event::DropFile` -[PR #733](https://github.com/Rust-SDL2/rust-sdl2/pull/733) -* Add `video::border_size -> Result<(u16, u16, u16, u16), String>` equivalent of `SDL_GetWindowBorderSize()` +[PR #789](https://github.com/Rust-SDL2/rust-sdl2/pull/789): Audio Safety Fixes -[PR #732](https://github.com/Rust-SDL2/rust-sdl2/pull/732) -* Implemented `From<(u8, u8, u8)>` and `From<(u8, u8, u8, u8)>` for `pixels::Color`. +[PR #785](https://github.com/Rust-SDL2/rust-sdl2/pull/785): Vulkan Support + +[PR #782](https://github.com/Rust-SDL2/rust-sdl2/pull/782) +* Move ffi of features (mixer, ...) into `sys` +* Updated SDL2's default version to 2.0.8 + +[PR #780](https://github.com/Rust-SDL2/rust-sdl2/pull/780): Fixed a panic in `keyboard::Mod` + +[PR #775](https://github.com/Rust-SDL2/rust-sdl2/pull/775): Added `get_platform` + +[PR #774](https://github.com/Rust-SDL2/rust-sdl2/pull/774): `add_timer` is now must_use + +[PR #764](https://github.com/Rust-SDL2/rust-sdl2/pull/764): impl `Hash` for `Point` and `Rect` + +[PR #763](https://github.com/Rust-SDL2/rust-sdl2/pull/763): Allow `-sys` to build for `windows-gnu` target + +[PR #751](https://github.com/Rust-SDL2/rust-sdl2/pull/751): +**Breaking change** `gl_setswap_interval` now returns a `Result` instead of a `bool`. + +[PR #759](https://github.com/Rust-SDL2/rust-sdl2/pull/759): Expose Joystick power level + +[PR #751](https://github.com/Rust-SDL2/rust-sdl2/pull/751) +* Fix memory leak in `filesystem::base_path()` +* Fix memory leak on `ClipboardUtil::clipboard_text()` + +[PR #740](https://github.com/Rust-SDL2/rust-sdl2/pull/740): Implement Debug for Event + +[PR #737](https://github.com/Rust-SDL2/rust-sdl2/pull/737): +Fix `ClipboardUtil::set_clipboard_text` to return an Ok when it went well. + +[PR #733](https://github.com/Rust-SDL2/rust-sdl2/pull/733): +Add `video::border_size -> Result<(u16, u16, u16, u16), String>` equivalent of `SDL_GetWindowBorderSize()` + +[PR #732](https://github.com/Rust-SDL2/rust-sdl2/pull/732): +Implemented `From<(u8, u8, u8)>` and `From<(u8, u8, u8, u8)>` for `pixels::Color`. `Canvas.set_draw_color` can now be called with tuples or other types which implements `Into` [PR #279](https://github.com/Rust-SDL2/rust-sdl2/pull/729) diff --git a/examples/audio-whitenoise.rs b/examples/audio-whitenoise.rs index 287798e4..471e7dbc 100644 --- a/examples/audio-whitenoise.rs +++ b/examples/audio-whitenoise.rs @@ -16,7 +16,7 @@ impl AudioCallback for MyCallback { // Generate white noise for x in out.iter_mut() { - *x = (rng.next_f32()*2.0 - 1.0) * self.volume; + *x = (rng.gen_range(0.0, 2.0) - 1.0) * self.volume; } } } diff --git a/scripts/travis-install-sdl2.sh b/scripts/travis-install-sdl2.sh new file mode 100644 index 00000000..aa80ec3a --- /dev/null +++ b/scripts/travis-install-sdl2.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +set -xueo pipefail + +wget https://www.libsdl.org/release/SDL2-2.0.8.tar.gz -O sdl2.tar.gz +tar xzf sdl2.tar.gz +pushd SDL2-* && ./configure && make && sudo make install && popd +wget -q https://www.libsdl.org/projects/SDL_ttf/release/SDL2_ttf-2.0.14.tar.gz +wget -q https://www.libsdl.org/projects/SDL_image/release/SDL2_image-2.0.1.tar.gz +wget -q https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-2.0.2.tar.gz +wget -q -O SDL2_gfx-1.0.1.tar.gz https://sourceforge.net/projects/sdl2gfx/files/SDL2_gfx-1.0.1.tar.gz/download +tar xzf SDL2_ttf-*.tar.gz +tar xzf SDL2_image-*.tar.gz +tar xzf SDL2_mixer-*.tar.gz +tar xzf SDL2_gfx-*.tar.gz +pushd SDL2_ttf-* && ./configure && make && sudo make install && popd +pushd SDL2_image-* && ./configure && make && sudo make install && popd +pushd SDL2_mixer-* && ./configure && make && sudo make install && popd +pushd SDL2_gfx-* && ./autogen.sh && ./configure && make && sudo make install && popd diff --git a/sdl2-sys/Cargo.toml b/sdl2-sys/Cargo.toml index 31eeeeb0..5d01d784 100644 --- a/sdl2-sys/Cargo.toml +++ b/sdl2-sys/Cargo.toml @@ -2,11 +2,11 @@ name = "sdl2-sys" description = "Raw SDL2 bindings for Rust, used internally rust-sdl2" -repository = "https://github.com/AngryLawyer/rust-sdl2" -version = "0.31.0" +repository = "https://github.com/rust-sdl2/rust-sdl2" +version = "0.32.1" authors = ["Tony Aldridge "] keywords = ["SDL", "windowing", "graphics", "ffi"] -categories = ["rendering","games","external-ffi-bindings","game-engines","multimedia"] +categories = ["rendering","external-ffi-bindings","game-engines","multimedia"] license = "MIT" links = "SDL2" build = "build.rs" @@ -16,31 +16,35 @@ name = "sdl2_sys" path = "src/lib.rs" [build-dependencies.bindgen] -version = "0.35" +version = "^0.42" optional = true [build-dependencies.pkg-config] -version = "0.3.9" +version = "^0.3" optional = true [build-dependencies.cmake] -version = "0.1" +version = "^0.1" optional = true [build-dependencies.reqwest] -version = "0.7" +version = "^0.9" optional = true [build-dependencies.tar] -version = "0.4" +version = "^0.4" optional = true [build-dependencies.flate2] -version = "0.2" +version = "^1" +optional = true + +[build-dependencies.unidiff] +version = "^0.2" optional = true [build-dependencies] -cfg-if = "0.1" +cfg-if = "^0.1" [features] @@ -49,7 +53,7 @@ use-pkgconfig = ["pkg-config"] use-bindgen = ["bindgen"] static-link = [] use_mac_framework = [] -bundled = ["cmake", "reqwest", "tar", "flate2"] +bundled = ["cmake", "reqwest", "tar", "flate2", "unidiff"] mixer = [] image = [] ttf = [] diff --git a/sdl2-sys/build.rs b/sdl2-sys/build.rs index 5b182008..3931f254 100644 --- a/sdl2-sys/build.rs +++ b/sdl2-sys/build.rs @@ -12,6 +12,8 @@ extern crate tar; extern crate flate2; #[cfg(feature="bundled")] extern crate reqwest; +#[cfg(feature="bundled")] +extern crate unidiff; #[macro_use] extern crate cfg_if; @@ -20,10 +22,10 @@ use std::path::{Path, PathBuf}; use std::{io, fs, env}; // corresponds to the headers that we have in sdl2-sys/SDL2-{version} -const SDL2_HEADERS_BUNDLED_VERSION: &str = "2.0.8"; +const SDL2_HEADERS_BUNDLED_VERSION: &str = "2.0.5"; // means the lastest stable version that can be downloaded from SDL2's source -const LASTEST_SDL2_VERSION: &str = "2.0.8"; +const LASTEST_SDL2_VERSION: &str = "2.0.5"; #[cfg(feature = "bindgen")] macro_rules! add_msvc_includes_to_bindings { @@ -41,9 +43,13 @@ fn download_to(url: &str, mut dest: T) { use io::BufRead; let resp = reqwest::get(url).expect(&format!("Failed to GET resource: {:?}", url)); - let size = resp.headers() - .get::() - .map(|ct_len| **ct_len) + let size: u32 = resp.headers() + .get(reqwest::header::CONTENT_LENGTH) + .and_then(|cl| { + cl.to_str().ok().and_then(|cl| { + cl.parse::().ok() + }) + }) .unwrap_or(0); if !resp.status().is_success() { panic!("Download request failed with status: {:?}", resp.status()) } if size == 0 { panic!("Size of content was returned was 0") } @@ -105,13 +111,133 @@ fn download_sdl2() -> PathBuf { let reader = flate2::read::GzDecoder::new( fs::File::open(&sdl2_archive_path).unwrap() - ).unwrap(); + ); let mut ar = tar::Archive::new(reader); ar.unpack(&out_dir).unwrap(); sdl2_build_path } +// apply patches to sdl2 source +#[cfg(feature = "bundled")] +fn patch_sdl2(sdl2_source_path: &Path) { + // vector of <(patch_file_name, patch_file_contents)> + let patches: Vec<(&str, &'static str)> = vec![ + // This patch fixes a CMake installation bug introduced in SDL2 2.0.4 on + // the Mac OS platform. Without this patch, the libSDL2.dylib generated + // during the SDL2 build phase will be overwritten by a symlink pointing + // to nothing. A variation of this patch was accepted upstream and + // should be included in SDL2 2.0.9. + // https://bugzilla.libsdl.org/show_bug.cgi?id=4234 + ("SDL2-2.0.8-4234-mac-os-dylib-fix.patch", include_str!("patches/SDL2-2.0.8-4234-mac-os-dylib-fix.patch")), + ]; + let sdl_version = format!("SDL2-{}", LASTEST_SDL2_VERSION); + + for patch in &patches { + // Only apply patches whose file name is prefixed with the currently + // targeted version of SDL2. + if !patch.0.starts_with(&sdl_version) { + continue; + } + let mut patch_set = unidiff::PatchSet::new(); + patch_set.parse(patch.1).expect("Error parsing diff"); + + // For every modified file, copy the existing file to _old, + // open a new copy of . and fill the new file with a + // combination of the unmodified contents, and the patched sections. + // TOOD: This code is untested (save for the immediate application), and + // probably belongs in the unidiff (or similar) package. + for modified_file in patch_set.modified_files() { + use std::io::{Write, BufRead}; + + let file_path = sdl2_source_path.join(modified_file.path()); + let old_path = sdl2_source_path.join(format!("{}_old", modified_file.path())); + fs::rename(&file_path, &old_path) + .expect(&format!( + "Rename of {} to {} failed", + file_path.to_string_lossy(), + old_path.to_string_lossy())); + + let dst_file = fs::File::create(file_path).unwrap(); + let mut dst_buf = io::BufWriter::new(dst_file); + let old_file = fs::File::open(old_path).unwrap(); + let mut old_buf = io::BufReader::new(old_file); + let mut cursor = 0; + + for (i, hunk) in modified_file.into_iter().enumerate() { + // Write old lines from cursor to the start of this hunk. + let num_lines = hunk.source_start - cursor - 1; + for _ in 0..num_lines { + let mut line = String::new(); + old_buf.read_line(&mut line).unwrap(); + dst_buf.write_all(line.as_bytes()).unwrap(); + } + cursor += num_lines; + + // Skip lines in old_file, and verify that what we expect to + // replace is present in the old_file. + for expected_line in hunk.source_lines() { + let mut actual_line = String::new(); + old_buf.read_line(&mut actual_line).unwrap(); + actual_line.pop(); // Remove the trailing newline. + if expected_line.value != actual_line { + panic!("Can't apply patch; mismatch between expected and actual in hunk {}", i); + } + } + cursor += hunk.source_length; + + // Write the new lines into the destination. + for line in hunk.target_lines() { + dst_buf.write_all(line.value.as_bytes()).unwrap(); + dst_buf.write_all(b"\n").unwrap(); + } + } + + // Write all remaining lines from the old file into the new. + for line in old_buf.lines() { + dst_buf.write_all(&line.unwrap().into_bytes()).unwrap(); + dst_buf.write_all(b"\n").unwrap(); + } + } + // For every removed file, simply delete the original. + // TODO: This is entirely untested code. There are likely bugs here, and + // this really should be part of the unidiff library, not a function + // defined here. Hopefully this gets moved somewhere else before it + // bites someone. + for removed_file in patch_set.removed_files() { + fs::remove_file(sdl2_source_path.join(removed_file.path())) + .expect( + &format!("Failed to remove file {} from {}", + removed_file.path(), + sdl2_source_path.to_string_lossy())); + } + // For every new file, copy the entire contents of the patched file into + // a newly created . + // TODO: This is entirely untested code. There are likely bugs here, and + // this really should be part of the unidiff library, not a function + // defined here. Hopefully this gets moved somewhere else before it + // bites someone. + for added_file in patch_set.added_files() { + use std::io::Write; + + // This should be superfluous. I don't know how a new file would + // ever have more than one hunk. + assert!(added_file.len() == 1); + let file_path = sdl2_source_path.join(added_file.path()); + let mut dst_file = fs::File::create(&file_path) + .expect(&format!( + "Failed to create file {}", + file_path.to_string_lossy())); + let mut dst_buf = io::BufWriter::new(&dst_file); + + for line in added_file.into_iter().nth(0).unwrap().target_lines() { + dst_buf.write_all(line.value.as_bytes()).unwrap(); + dst_buf.write_all(b"\n").unwrap(); + } + } + } +} + // compile a shared or static lib depending on the feature #[cfg(feature = "bundled")] fn compile_sdl2(sdl2_build_path: &Path, target_os: &str) -> PathBuf { @@ -281,14 +407,60 @@ fn link_sdl2(target_os: &str) { } } +fn find_cargo_target_dir() -> PathBuf { + // Infer the top level cargo target dir from the OUT_DIR by searching + // upwards until we get to $CARGO_TARGET_DIR/build/ (which is always one + // level up from the deepest directory containing our package name) + let pkg_name = env::var("CARGO_PKG_NAME").unwrap(); + let mut out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + loop { + { + let final_path_segment = out_dir.file_name().unwrap(); + if final_path_segment.to_string_lossy().contains(&pkg_name) { + break; + } + } + if !out_dir.pop() { + panic!("Malformed build path: {}", out_dir.to_string_lossy()); + } + } + out_dir.pop(); + out_dir.pop(); + out_dir +} + +fn copy_dynamic_libraries(sdl2_compiled_path: &PathBuf, target_os: &str) { + // Windows binaries do not embed library search paths, so successfully + // linking the DLL isn't sufficient to find it at runtime -- it must be + // either on PATH or in the current working directory when we run binaries + // linked against it. In other words, to run the test suite we need to + // copy sdl2.dll out of its build tree and down to the top level cargo + // binary output directory. + if target_os.contains("windows") { + let sdl2_dll_name = "sdl2.dll"; + let sdl2_bin_path = sdl2_compiled_path.join("bin"); + let target_path = find_cargo_target_dir(); + + let src_dll_path = sdl2_bin_path.join(sdl2_dll_name); + let dst_dll_path = target_path.join(sdl2_dll_name); + + fs::copy(&src_dll_path, &dst_dll_path) + .expect(&format!("Failed to copy SDL2 dynamic library from {} to {}", + src_dll_path.to_string_lossy(), + dst_dll_path.to_string_lossy())); + } +} + fn main() { let target = env::var("TARGET").expect("Cargo build scripts always have TARGET"); let host = env::var("HOST").expect("Cargo build scripts always have HOST"); let target_os = get_os_from_triple(target.as_str()).unwrap(); + let sdl2_compiled_path: PathBuf; #[cfg(feature = "bundled")] { let sdl2_source_path = download_sdl2(); - let sdl2_compiled_path = compile_sdl2(sdl2_source_path.as_path(), target_os); + patch_sdl2(sdl2_source_path.as_path()); + sdl2_compiled_path = compile_sdl2(sdl2_source_path.as_path(), target_os); let sdl2_downloaded_include_path = sdl2_source_path.join("include"); let sdl2_compiled_lib_path = sdl2_compiled_path.join("lib"); @@ -311,6 +483,10 @@ fn main() { } link_sdl2(target_os); + + #[cfg(all(feature = "bundled", not(feature = "static-link")))] { + copy_dynamic_libraries(&sdl2_compiled_path, target_os); + } } #[cfg(not(feature = "bindgen"))] diff --git a/sdl2-sys/patches/SDL2-2.0.8-4234-mac-os-dylib-fix.patch b/sdl2-sys/patches/SDL2-2.0.8-4234-mac-os-dylib-fix.patch new file mode 100644 index 00000000..5f05f5ce --- /dev/null +++ b/sdl2-sys/patches/SDL2-2.0.8-4234-mac-os-dylib-fix.patch @@ -0,0 +1,44 @@ +# HG changeset patch +# User Drew Pirrone-Brusse +# Date 1537744393 14400 +# Sun Sep 23 19:13:13 2018 -0400 +# Node ID b66fb83b6897137c1c2b857ee5490e602f8c31b0 +# Parent f1084c419f33610cf274e309a8b2798d2ae665c7 +Correct the name of the SDL shared library in CMake for Mac OS + +diff -r f1084c419f33 -r b66fb83b6897 CMakeLists.txt +--- a/CMakeLists.txt Thu Mar 01 08:26:10 2018 -0800 ++++ b/CMakeLists.txt Sun Sep 23 19:13:13 2018 -0400 +@@ -1704,7 +1704,9 @@ + if(SDL_SHARED) + add_library(SDL2 SHARED ${SOURCE_FILES} ${VERSION_SOURCES}) + if(APPLE) +- set_target_properties(SDL2 PROPERTIES MACOSX_RPATH 1) ++ set_target_properties(SDL2 PROPERTIES ++ MACOSX_RPATH 1 ++ OUTPUT_NAME "SDL2-${LT_RELEASE}") + elseif(UNIX AND NOT ANDROID) + set_target_properties(SDL2 PROPERTIES + VERSION ${LT_VERSION} +@@ -1810,16 +1812,14 @@ + + if(NOT (WINDOWS OR CYGWIN)) + if(SDL_SHARED) +- if (APPLE) +- set(SOEXT "dylib") +- else() +- set(SOEXT "so") +- endif() ++ set(SOEXT ${CMAKE_SHARED_LIBRARY_SUFFIX}) # ".so", ".dylib", etc. ++ get_target_property(SONAME SDL2 OUTPUT_NAME) + if(NOT ANDROID) + install(CODE " + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink +- \"libSDL2-2.0.${SOEXT}\" \"libSDL2.${SOEXT}\")") +- install(FILES ${SDL2_BINARY_DIR}/libSDL2.${SOEXT} DESTINATION "lib${LIB_SUFFIX}") ++ \"lib${SONAME}${SOPOSTFIX}${SOEXT}\" \"libSDL2${SOPOSTFIX}${SOEXT}\")" ++ WORKING_DIR "${SDL2_BINARY_DIR}") ++ install(FILES ${SDL2_BINARY_DIR}/libSDL2${SOPOSTFIX}${SOEXT} DESTINATION "lib${LIB_SUFFIX}") + endif() + endif() + if(FREEBSD) diff --git a/sdl2-sys/sdl_bindings.rs b/sdl2-sys/sdl_bindings.rs index 48975838..dd7ad950 100644 --- a/sdl2-sys/sdl_bindings.rs +++ b/sdl2-sys/sdl_bindings.rs @@ -41,7 +41,7 @@ pub const __STDC_ISO_10646__: u32 = 201706; pub const __STDC_NO_THREADS__: u32 = 1; pub const __GNU_LIBRARY__: u32 = 6; pub const __GLIBC__: u32 = 2; -pub const __GLIBC_MINOR__: u32 = 26; +pub const __GLIBC_MINOR__: u32 = 27; pub const _SYS_CDEFS_H: u32 = 1; pub const __glibc_c99_flexarr_available: u32 = 1; pub const __WORDSIZE: u32 = 64; @@ -168,10 +168,25 @@ pub const WNOWAIT: u32 = 16777216; pub const __WNOTHREAD: u32 = 536870912; pub const __WALL: u32 = 1073741824; pub const __WCLONE: u32 = 2147483648; +pub const __ENUM_IDTYPE_T: u32 = 1; pub const __W_CONTINUED: u32 = 65535; pub const __WCOREFLAG: u32 = 128; pub const __HAVE_FLOAT128: u32 = 0; pub const __HAVE_DISTINCT_FLOAT128: u32 = 0; +pub const __HAVE_FLOAT64X: u32 = 1; +pub const __HAVE_FLOAT64X_LONG_DOUBLE: u32 = 1; +pub const __HAVE_FLOAT16: u32 = 0; +pub const __HAVE_FLOAT32: u32 = 1; +pub const __HAVE_FLOAT64: u32 = 1; +pub const __HAVE_FLOAT32X: u32 = 1; +pub const __HAVE_FLOAT128X: u32 = 0; +pub const __HAVE_DISTINCT_FLOAT16: u32 = 0; +pub const __HAVE_DISTINCT_FLOAT32: u32 = 0; +pub const __HAVE_DISTINCT_FLOAT64: u32 = 0; +pub const __HAVE_DISTINCT_FLOAT32X: u32 = 0; +pub const __HAVE_DISTINCT_FLOAT64X: u32 = 0; +pub const __HAVE_DISTINCT_FLOAT128X: u32 = 0; +pub const __HAVE_FLOATN_NOT_TYPEDEF: u32 = 0; pub const __ldiv_t_defined: u32 = 1; pub const __lldiv_t_defined: u32 = 1; pub const RAND_MAX: u32 = 2147483647; @@ -210,6 +225,8 @@ pub const __PTHREAD_RWLOCK_INT_FLAGS_SHARED: u32 = 1; pub const __PTHREAD_MUTEX_HAVE_PREV: u32 = 1; pub const __have_pthread_attr_t: u32 = 1; pub const _ALLOCA_H: u32 = 1; +pub const _MM_HINT_ET0: u32 = 7; +pub const _MM_HINT_ET1: u32 = 6; pub const _MM_HINT_T0: u32 = 3; pub const _MM_HINT_T1: u32 = 2; pub const _MM_HINT_T2: u32 = 1; @@ -311,6 +328,8 @@ pub const SDL_HINT_VIDEO_X11_XVIDMODE: &'static [u8; 23usize] = b"SDL_VIDEO_X11_ pub const SDL_HINT_VIDEO_X11_XINERAMA: &'static [u8; 23usize] = b"SDL_VIDEO_X11_XINERAMA\0"; pub const SDL_HINT_VIDEO_X11_XRANDR: &'static [u8; 21usize] = b"SDL_VIDEO_X11_XRANDR\0"; pub const SDL_HINT_VIDEO_X11_NET_WM_PING: &'static [u8; 26usize] = b"SDL_VIDEO_X11_NET_WM_PING\0"; +pub const SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR: &'static [u8; 39usize] = + b"SDL_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR\0"; pub const SDL_HINT_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN: &'static [u8; 44usize] = b"SDL_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN\0"; pub const SDL_HINT_WINDOWS_INTRESOURCE_ICON: &'static [u8; 29usize] = @@ -337,8 +356,11 @@ pub const SDL_HINT_APPLE_TV_CONTROLLER_UI_EVENTS: &'static [u8; 34usize] = b"SDL_APPLE_TV_CONTROLLER_UI_EVENTS\0"; pub const SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION: &'static [u8; 35usize] = b"SDL_APPLE_TV_REMOTE_ALLOW_ROTATION\0"; +pub const SDL_HINT_IOS_HIDE_HOME_INDICATOR: &'static [u8; 28usize] = + b"SDL_IOS_HIDE_HOME_INDICATOR\0"; pub const SDL_HINT_ACCELEROMETER_AS_JOYSTICK: &'static [u8; 30usize] = b"SDL_ACCELEROMETER_AS_JOYSTICK\0"; +pub const SDL_HINT_TV_REMOTE_AS_JOYSTICK: &'static [u8; 26usize] = b"SDL_TV_REMOTE_AS_JOYSTICK\0"; pub const SDL_HINT_XINPUT_ENABLED: &'static [u8; 19usize] = b"SDL_XINPUT_ENABLED\0"; pub const SDL_HINT_XINPUT_USE_OLD_JOYSTICK_MAPPING: &'static [u8; 36usize] = b"SDL_XINPUT_USE_OLD_JOYSTICK_MAPPING\0"; @@ -377,6 +399,7 @@ pub const SDL_HINT_ANDROID_APK_EXPANSION_PATCH_FILE_VERSION: &'static [u8; 45usi pub const SDL_HINT_IME_INTERNAL_EDITING: &'static [u8; 25usize] = b"SDL_IME_INTERNAL_EDITING\0"; pub const SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH: &'static [u8; 37usize] = b"SDL_ANDROID_SEPARATE_MOUSE_AND_TOUCH\0"; +pub const SDL_HINT_RETURN_KEY_HIDES_IME: &'static [u8; 25usize] = b"SDL_RETURN_KEY_HIDES_IME\0"; pub const SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT: &'static [u8; 32usize] = b"SDL_EMSCRIPTEN_KEYBOARD_ELEMENT\0"; pub const SDL_HINT_NO_SIGNAL_HANDLERS: &'static [u8; 23usize] = b"SDL_NO_SIGNAL_HANDLERS\0"; @@ -386,6 +409,7 @@ pub const SDL_HINT_BMP_SAVE_LEGACY_FORMAT: &'static [u8; 27usize] = b"SDL_BMP_SA pub const SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING: &'static [u8; 34usize] = b"SDL_WINDOWS_DISABLE_THREAD_NAMING\0"; pub const SDL_HINT_RPI_VIDEO_LAYER: &'static [u8; 20usize] = b"SDL_RPI_VIDEO_LAYER\0"; +pub const SDL_HINT_VIDEO_DOUBLE_BUFFER: &'static [u8; 24usize] = b"SDL_VIDEO_DOUBLE_BUFFER\0"; pub const SDL_HINT_OPENGL_ES_DRIVER: &'static [u8; 21usize] = b"SDL_OPENGL_ES_DRIVER\0"; pub const SDL_HINT_AUDIO_RESAMPLING_MODE: &'static [u8; 26usize] = b"SDL_AUDIO_RESAMPLING_MODE\0"; pub const SDL_HINT_AUDIO_CATEGORY: &'static [u8; 19usize] = b"SDL_AUDIO_CATEGORY\0"; @@ -395,7 +419,7 @@ pub const SDL_INVALID_SHAPE_ARGUMENT: i32 = -2; pub const SDL_WINDOW_LACKS_SHAPE: i32 = -3; pub const SDL_MAJOR_VERSION: u32 = 2; pub const SDL_MINOR_VERSION: u32 = 0; -pub const SDL_PATCHLEVEL: u32 = 6; +pub const SDL_PATCHLEVEL: u32 = 8; pub const SDL_INIT_TIMER: u32 = 1; pub const SDL_INIT_AUDIO: u32 = 16; pub const SDL_INIT_VIDEO: u32 = 32; @@ -942,7 +966,6 @@ pub type __ssize_t = ::std::os::raw::c_long; pub type __syscall_slong_t = ::std::os::raw::c_long; pub type __syscall_ulong_t = ::std::os::raw::c_ulong; pub type __loff_t = __off64_t; -pub type __qaddr_t = *mut __quad_t; pub type __caddr_t = *mut ::std::os::raw::c_char; pub type __intptr_t = ::std::os::raw::c_long; pub type __socklen_t = ::std::os::raw::c_uint; @@ -971,21 +994,13 @@ pub enum SDL_bool { SDL_FALSE = 0, SDL_TRUE = 1, } -/// \brief A signed 8-bit integer type. pub type Sint8 = i8; -/// \brief An unsigned 8-bit integer type. pub type Uint8 = u8; -/// \brief A signed 16-bit integer type. pub type Sint16 = i16; -/// \brief An unsigned 16-bit integer type. pub type Uint16 = u16; -/// \brief A signed 32-bit integer type. pub type Sint32 = i32; -/// \brief An unsigned 32-bit integer type. pub type Uint32 = u32; -/// \brief A signed 64-bit integer type. pub type Sint64 = i64; -/// \brief An unsigned 64-bit integer type. pub type Uint64 = u64; pub type SDL_compile_time_assert_uint8 = [::std::os::raw::c_int; 1usize]; pub type SDL_compile_time_assert_sint8 = [::std::os::raw::c_int; 1usize]; @@ -1016,6 +1031,44 @@ extern "C" { extern "C" { pub fn SDL_free(mem: *mut ::std::os::raw::c_void); } +pub type SDL_malloc_func = + ::std::option::Option *mut ::std::os::raw::c_void>; +pub type SDL_calloc_func = ::std::option::Option< + unsafe extern "C" fn(nmemb: usize, size: usize) -> *mut ::std::os::raw::c_void, +>; +pub type SDL_realloc_func = ::std::option::Option< + unsafe extern "C" fn(mem: *mut ::std::os::raw::c_void, size: usize) + -> *mut ::std::os::raw::c_void, +>; +pub type SDL_free_func = + ::std::option::Option; +extern "C" { + /// \brief Get the current set of SDL memory functions + pub fn SDL_GetMemoryFunctions( + malloc_func: *mut SDL_malloc_func, + calloc_func: *mut SDL_calloc_func, + realloc_func: *mut SDL_realloc_func, + free_func: *mut SDL_free_func, + ); +} +extern "C" { + /// \brief Replace SDL's memory allocation functions with a custom set + /// + /// \note If you are replacing SDL's memory functions, you should call + /// SDL_GetNumAllocations() and be very careful if it returns non-zero. + /// That means that your free function will be called with memory + /// allocated by the previous memory allocation functions. + pub fn SDL_SetMemoryFunctions( + malloc_func: SDL_malloc_func, + calloc_func: SDL_calloc_func, + realloc_func: SDL_realloc_func, + free_func: SDL_free_func, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// \brief Get the number of outstanding (unfreed) allocations + pub fn SDL_GetNumAllocations() -> ::std::os::raw::c_int; +} extern "C" { pub fn SDL_getenv(name: *const ::std::os::raw::c_char) -> *mut ::std::os::raw::c_char; } @@ -1292,21 +1345,39 @@ extern "C" { extern "C" { pub fn SDL_acos(x: f64) -> f64; } +extern "C" { + pub fn SDL_acosf(x: f32) -> f32; +} extern "C" { pub fn SDL_asin(x: f64) -> f64; } +extern "C" { + pub fn SDL_asinf(x: f32) -> f32; +} extern "C" { pub fn SDL_atan(x: f64) -> f64; } +extern "C" { + pub fn SDL_atanf(x: f32) -> f32; +} extern "C" { pub fn SDL_atan2(x: f64, y: f64) -> f64; } +extern "C" { + pub fn SDL_atan2f(x: f32, y: f32) -> f32; +} extern "C" { pub fn SDL_ceil(x: f64) -> f64; } +extern "C" { + pub fn SDL_ceilf(x: f32) -> f32; +} extern "C" { pub fn SDL_copysign(x: f64, y: f64) -> f64; } +extern "C" { + pub fn SDL_copysignf(x: f32, y: f32) -> f32; +} extern "C" { pub fn SDL_cos(x: f64) -> f64; } @@ -1316,18 +1387,45 @@ extern "C" { extern "C" { pub fn SDL_fabs(x: f64) -> f64; } +extern "C" { + pub fn SDL_fabsf(x: f32) -> f32; +} extern "C" { pub fn SDL_floor(x: f64) -> f64; } +extern "C" { + pub fn SDL_floorf(x: f32) -> f32; +} +extern "C" { + pub fn SDL_fmod(x: f64, y: f64) -> f64; +} +extern "C" { + pub fn SDL_fmodf(x: f32, y: f32) -> f32; +} extern "C" { pub fn SDL_log(x: f64) -> f64; } +extern "C" { + pub fn SDL_logf(x: f32) -> f32; +} +extern "C" { + pub fn SDL_log10(x: f64) -> f64; +} +extern "C" { + pub fn SDL_log10f(x: f32) -> f32; +} extern "C" { pub fn SDL_pow(x: f64, y: f64) -> f64; } +extern "C" { + pub fn SDL_powf(x: f32, y: f32) -> f32; +} extern "C" { pub fn SDL_scalbn(x: f64, n: ::std::os::raw::c_int) -> f64; } +extern "C" { + pub fn SDL_scalbnf(x: f32, n: ::std::os::raw::c_int) -> f32; +} extern "C" { pub fn SDL_sin(x: f64) -> f64; } @@ -2482,6 +2580,15 @@ pub type SDL_AudioCallback = ::std::option::Option< ), >; /// The calculated values in this structure are calculated by SDL_OpenAudio(). +/// +/// For multi-channel audio, the default SDL channel mapping is: +/// 2: FL FR (stereo) +/// 3: FL FR LFE (2.1 surround) +/// 4: FL FR BL BR (quad) +/// 5: FL FR FC BL BR (quad + center) +/// 6: FL FR FC LFE SL SR (5.1 surround - last two can also be BL BR) +/// 7: FL FR FC LFE BC SL SR (6.1 surround) +/// 8: FL FR FC LFE BL BR SL SR (7.1 surround) #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct SDL_AudioSpec { @@ -2962,6 +3069,130 @@ extern "C" { /// \return 0 on success or -1 if \c cvt->buf is NULL. pub fn SDL_ConvertAudio(cvt: *mut SDL_AudioCVT) -> ::std::os::raw::c_int; } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SDL_AudioStream { + _unused: [u8; 0], +} +pub type SDL_AudioStream = _SDL_AudioStream; +extern "C" { + /// Create a new audio stream + /// + /// \param src_format The format of the source audio + /// \param src_channels The number of channels of the source audio + /// \param src_rate The sampling rate of the source audio + /// \param dst_format The format of the desired audio output + /// \param dst_channels The number of channels of the desired audio output + /// \param dst_rate The sampling rate of the desired audio output + /// \return 0 on success, or -1 on error. + /// + /// \sa SDL_AudioStreamPut + /// \sa SDL_AudioStreamGet + /// \sa SDL_AudioStreamAvailable + /// \sa SDL_AudioStreamFlush + /// \sa SDL_AudioStreamClear + /// \sa SDL_FreeAudioStream + pub fn SDL_NewAudioStream( + src_format: SDL_AudioFormat, + src_channels: Uint8, + src_rate: ::std::os::raw::c_int, + dst_format: SDL_AudioFormat, + dst_channels: Uint8, + dst_rate: ::std::os::raw::c_int, + ) -> *mut SDL_AudioStream; +} +extern "C" { + /// Add data to be converted/resampled to the stream + /// + /// \param stream The stream the audio data is being added to + /// \param buf A pointer to the audio data to add + /// \param len The number of bytes to write to the stream + /// \return 0 on success, or -1 on error. + /// + /// \sa SDL_NewAudioStream + /// \sa SDL_AudioStreamGet + /// \sa SDL_AudioStreamAvailable + /// \sa SDL_AudioStreamFlush + /// \sa SDL_AudioStreamClear + /// \sa SDL_FreeAudioStream + pub fn SDL_AudioStreamPut( + stream: *mut SDL_AudioStream, + buf: *const ::std::os::raw::c_void, + len: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// Get converted/resampled data from the stream + /// + /// \param stream The stream the audio is being requested from + /// \param buf A buffer to fill with audio data + /// \param len The maximum number of bytes to fill + /// \return The number of bytes read from the stream, or -1 on error + /// + /// \sa SDL_NewAudioStream + /// \sa SDL_AudioStreamPut + /// \sa SDL_AudioStreamAvailable + /// \sa SDL_AudioStreamFlush + /// \sa SDL_AudioStreamClear + /// \sa SDL_FreeAudioStream + pub fn SDL_AudioStreamGet( + stream: *mut SDL_AudioStream, + buf: *mut ::std::os::raw::c_void, + len: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// Get the number of converted/resampled bytes available. The stream may be + /// buffering data behind the scenes until it has enough to resample + /// correctly, so this number might be lower than what you expect, or even + /// be zero. Add more data or flush the stream if you need the data now. + /// + /// \sa SDL_NewAudioStream + /// \sa SDL_AudioStreamPut + /// \sa SDL_AudioStreamGet + /// \sa SDL_AudioStreamFlush + /// \sa SDL_AudioStreamClear + /// \sa SDL_FreeAudioStream + pub fn SDL_AudioStreamAvailable(stream: *mut SDL_AudioStream) -> ::std::os::raw::c_int; +} +extern "C" { + /// Tell the stream that you're done sending data, and anything being buffered + /// should be converted/resampled and made available immediately. + /// + /// It is legal to add more data to a stream after flushing, but there will + /// be audio gaps in the output. Generally this is intended to signal the + /// end of input, so the complete output becomes available. + /// + /// \sa SDL_NewAudioStream + /// \sa SDL_AudioStreamPut + /// \sa SDL_AudioStreamGet + /// \sa SDL_AudioStreamAvailable + /// \sa SDL_AudioStreamClear + /// \sa SDL_FreeAudioStream + pub fn SDL_AudioStreamFlush(stream: *mut SDL_AudioStream) -> ::std::os::raw::c_int; +} +extern "C" { + /// Clear any pending data in the stream without converting it + /// + /// \sa SDL_NewAudioStream + /// \sa SDL_AudioStreamPut + /// \sa SDL_AudioStreamGet + /// \sa SDL_AudioStreamAvailable + /// \sa SDL_AudioStreamFlush + /// \sa SDL_FreeAudioStream + pub fn SDL_AudioStreamClear(stream: *mut SDL_AudioStream); +} +extern "C" { + /// Free an audio stream + /// + /// \sa SDL_NewAudioStream + /// \sa SDL_AudioStreamPut + /// \sa SDL_AudioStreamGet + /// \sa SDL_AudioStreamAvailable + /// \sa SDL_AudioStreamFlush + /// \sa SDL_AudioStreamClear + pub fn SDL_FreeAudioStream(stream: *mut SDL_AudioStream); +} extern "C" { /// This takes two audio buffers of the playing audio format and mixes /// them, performing addition, volume adjustment, and overflow clipping. @@ -3021,7 +3252,7 @@ extern "C" { /// \param dev The device ID to which we will queue audio. /// \param data The data to queue to the device for later playback. /// \param len The number of bytes (not samples!) to which (data) points. - /// \return zero on success, -1 on error. + /// \return 0 on success, or -1 on error. /// /// \sa SDL_GetQueuedAudioSize /// \sa SDL_ClearQueuedAudio @@ -3196,6 +3427,17 @@ pub type __v4si = [::std::os::raw::c_int; 4usize]; pub type __v4sf = [f32; 4usize]; pub type __m128 = [f32; 4usize]; pub type __v4su = [::std::os::raw::c_uint; 4usize]; +#[repr(u32)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum idtype_t { + P_ALL = 0, + P_PID = 1, + P_PGID = 2, +} +pub type _Float32 = f32; +pub type _Float64 = f64; +pub type _Float32x = f64; +pub type _Float64x = f64; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct div_t { @@ -5372,6 +5614,7 @@ pub const SDL_PIXELFORMAT_UYVY: _bindgen_ty_6 = _bindgen_ty_6::SDL_PIXELFORMAT_U pub const SDL_PIXELFORMAT_YVYU: _bindgen_ty_6 = _bindgen_ty_6::SDL_PIXELFORMAT_YVYU; pub const SDL_PIXELFORMAT_NV12: _bindgen_ty_6 = _bindgen_ty_6::SDL_PIXELFORMAT_NV12; pub const SDL_PIXELFORMAT_NV21: _bindgen_ty_6 = _bindgen_ty_6::SDL_PIXELFORMAT_NV21; +pub const SDL_PIXELFORMAT_EXTERNAL_OES: _bindgen_ty_6 = _bindgen_ty_6::SDL_PIXELFORMAT_EXTERNAL_OES; #[repr(u32)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum _bindgen_ty_6 { @@ -5420,6 +5663,8 @@ pub enum _bindgen_ty_6 { SDL_PIXELFORMAT_NV12 = 842094158, /// < Planar mode: Y + V/U interleaved (2 planes) SDL_PIXELFORMAT_NV21 = 825382478, + /// < Android video texture format + SDL_PIXELFORMAT_EXTERNAL_OES = 542328143, } #[repr(C)] #[derive(Debug, Copy, Clone)] @@ -6312,6 +6557,19 @@ pub type SDL_blit = ::std::option::Option< dstrect: *mut SDL_Rect, ) -> ::std::os::raw::c_int, >; +#[repr(u32)] +/// \brief The formula used for converting between YUV and RGB +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum SDL_YUV_CONVERSION_MODE { + /// < Full range JPEG + SDL_YUV_CONVERSION_JPEG = 0, + /// < BT.601 (the default) + SDL_YUV_CONVERSION_BT601 = 1, + /// < BT.709 + SDL_YUV_CONVERSION_BT709 = 2, + /// < BT.601 for SD content, BT.709 for HD content + SDL_YUV_CONVERSION_AUTOMATIC = 3, +} extern "C" { /// Allocate and free an RGB surface. /// @@ -6703,6 +6961,21 @@ extern "C" { dstrect: *mut SDL_Rect, ) -> ::std::os::raw::c_int; } +extern "C" { + /// \brief Set the YUV conversion mode + pub fn SDL_SetYUVConversionMode(mode: SDL_YUV_CONVERSION_MODE); +} +extern "C" { + /// \brief Get the YUV conversion mode + pub fn SDL_GetYUVConversionMode() -> SDL_YUV_CONVERSION_MODE; +} +extern "C" { + /// \brief Get the YUV conversion mode, returning the correct mode for the resolution when the current conversion mode is SDL_YUV_CONVERSION_AUTOMATIC + pub fn SDL_GetYUVConversionModeForResolution( + width: ::std::os::raw::c_int, + height: ::std::os::raw::c_int, + ) -> SDL_YUV_CONVERSION_MODE; +} /// \brief The structure that defines a display mode /// /// \sa SDL_GetNumDisplayModes() @@ -6825,7 +7098,9 @@ pub enum SDL_WindowFlags { SDL_WINDOW_FULLSCREEN_DESKTOP = 4097, /// < window not created by SDL SDL_WINDOW_FOREIGN = 2048, - /// < window should be created in high-DPI mode if supported + /// < window should be created in high-DPI mode if supported. + /// On macOS NSHighResolutionCapable must be set true in the + /// application's Info.plist for this to have any effect. SDL_WINDOW_ALLOW_HIGHDPI = 8192, /// < window has mouse captured (unrelated to INPUT_GRABBED) SDL_WINDOW_MOUSE_CAPTURE = 16384, @@ -7190,7 +7465,7 @@ extern "C" { /// If the window is created with any of the SDL_WINDOW_OPENGL or /// SDL_WINDOW_VULKAN flags, then the corresponding LoadLibrary function /// (SDL_GL_LoadLibrary or SDL_Vulkan_LoadLibrary) is called and the - /// corrensponding UnloadLibrary function is called by SDL_DestroyWindow(). + /// corresponding UnloadLibrary function is called by SDL_DestroyWindow(). /// /// If SDL_WINDOW_VULKAN is specified and there isn't a working Vulkan driver, /// SDL_CreateWindow() will fail because SDL_Vulkan_LoadLibrary() will fail. @@ -9312,6 +9587,20 @@ pub enum SDL_JoystickPowerLevel { SDL_JOYSTICK_POWER_WIRED = 4, SDL_JOYSTICK_POWER_MAX = 5, } +extern "C" { + /// Locking for multi-threaded access to the joystick API + /// + /// If you are using the joystick API or handling events from multiple threads + /// you should use these locking functions to protect access to the joysticks. + /// + /// In particular, you are guaranteed that the joystick list won't change, so + /// the API functions that take a joystick index will be valid, and joystick + /// and game controller events will not be delivered. + pub fn SDL_LockJoysticks(); +} +extern "C" { + pub fn SDL_UnlockJoysticks(); +} extern "C" { /// Count the number of joysticks attached to the system right now pub fn SDL_NumJoysticks() -> ::std::os::raw::c_int; @@ -16423,6 +16712,28 @@ extern "C" { /// \return 0 on success, or -1 if the operation is not supported pub fn SDL_GL_UnbindTexture(texture: *mut SDL_Texture) -> ::std::os::raw::c_int; } +extern "C" { + /// \brief Get the CAMetalLayer associated with the given Metal renderer + /// + /// \param renderer The renderer to query + /// + /// \return CAMetalLayer* on success, or NULL if the renderer isn't a Metal renderer + /// + /// \sa SDL_RenderGetMetalCommandEncoder() + pub fn SDL_RenderGetMetalLayer(renderer: *mut SDL_Renderer) -> *mut ::std::os::raw::c_void; +} +extern "C" { + /// \brief Get the Metal command encoder for the current frame + /// + /// \param renderer The renderer to query + /// + /// \return id on success, or NULL if the renderer isn't a Metal renderer + /// + /// \sa SDL_RenderGetMetalLayer() + pub fn SDL_RenderGetMetalCommandEncoder( + renderer: *mut SDL_Renderer, + ) -> *mut ::std::os::raw::c_void; +} extern "C" { /// \brief Create a window that can be shaped with the specified position, dimensions, and flags. /// @@ -28967,6 +29278,218 @@ extern "C" { /// \endcode pub fn SDL_GetWindowWMInfo(window: *mut SDL_Window, info: *mut SDL_SysWMinfo) -> SDL_bool; } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct VkInstance_T { + _unused: [u8; 0], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct VkSurfaceKHR_T { + _unused: [u8; 0], +} +pub type SDL_vulkanInstance = VkInstance; +pub type SDL_vulkanSurface = VkSurfaceKHR; +extern "C" { + /// \brief Dynamically load a Vulkan loader library. + /// + /// \param [in] path The platform dependent Vulkan loader library name, or + /// \c NULL. + /// + /// \return \c 0 on success, or \c -1 if the library couldn't be loaded. + /// + /// If \a path is NULL SDL will use the value of the environment variable + /// \c SDL_VULKAN_LIBRARY, if set, otherwise it loads the default Vulkan + /// loader library. + /// + /// This should be called after initializing the video driver, but before + /// creating any Vulkan windows. If no Vulkan loader library is loaded, the + /// default library will be loaded upon creation of the first Vulkan window. + /// + /// \note It is fairly common for Vulkan applications to link with \a libvulkan + /// instead of explicitly loading it at run time. This will work with + /// SDL provided the application links to a dynamic library and both it + /// and SDL use the same search path. + /// + /// \note If you specify a non-NULL \c path, an application should retrieve all + /// of the Vulkan functions it uses from the dynamic library using + /// \c SDL_Vulkan_GetVkGetInstanceProcAddr() unless you can guarantee + /// \c path points to the same vulkan loader library the application + /// linked to. + /// + /// \note On Apple devices, if \a path is NULL, SDL will attempt to find + /// the vkGetInstanceProcAddr address within all the mach-o images of + /// the current process. This is because it is fairly common for Vulkan + /// applications to link with libvulkan (and historically MoltenVK was + /// provided as a static library). If it is not found then, on macOS, SDL + /// will attempt to load \c vulkan.framework/vulkan, \c libvulkan.1.dylib, + /// \c MoltenVK.framework/MoltenVK and \c libMoltenVK.dylib in that order. + /// On iOS SDL will attempt to load \c libMoltenVK.dylib. Applications + /// using a dynamic framework or .dylib must ensure it is included in its + /// application bundle. + /// + /// \note On non-Apple devices, application linking with a static libvulkan is + /// not supported. Either do not link to the Vulkan loader or link to a + /// dynamic library version. + /// + /// \note This function will fail if there are no working Vulkan drivers + /// installed. + /// + /// \sa SDL_Vulkan_GetVkGetInstanceProcAddr() + /// \sa SDL_Vulkan_UnloadLibrary() + pub fn SDL_Vulkan_LoadLibrary(path: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; +} +extern "C" { + /// \brief Get the address of the \c vkGetInstanceProcAddr function. + /// + /// \note This should be called after either calling SDL_Vulkan_LoadLibrary + /// or creating an SDL_Window with the SDL_WINDOW_VULKAN flag. + pub fn SDL_Vulkan_GetVkGetInstanceProcAddr() -> *mut ::std::os::raw::c_void; +} +extern "C" { + /// \brief Unload the Vulkan loader library previously loaded by + /// \c SDL_Vulkan_LoadLibrary(). + /// + /// \sa SDL_Vulkan_LoadLibrary() + pub fn SDL_Vulkan_UnloadLibrary(); +} +extern "C" { + /// \brief Get the names of the Vulkan instance extensions needed to create + /// a surface with \c SDL_Vulkan_CreateSurface(). + /// + /// \param [in] window Window for which the required Vulkan instance + /// extensions should be retrieved + /// \param [in,out] count pointer to an \c unsigned related to the number of + /// required Vulkan instance extensions + /// \param [out] names \c NULL or a pointer to an array to be filled with the + /// required Vulkan instance extensions + /// + /// \return \c SDL_TRUE on success, \c SDL_FALSE on error. + /// + /// If \a pNames is \c NULL, then the number of required Vulkan instance + /// extensions is returned in pCount. Otherwise, \a pCount must point to a + /// variable set to the number of elements in the \a pNames array, and on + /// return the variable is overwritten with the number of names actually + /// written to \a pNames. If \a pCount is less than the number of required + /// extensions, at most \a pCount structures will be written. If \a pCount + /// is smaller than the number of required extensions, \c SDL_FALSE will be + /// returned instead of \c SDL_TRUE, to indicate that not all the required + /// extensions were returned. + /// + /// \note The returned list of extensions will contain \c VK_KHR_surface + /// and zero or more platform specific extensions + /// + /// \note The extension names queried here must be enabled when calling + /// VkCreateInstance, otherwise surface creation will fail. + /// + /// \note \c window should have been created with the \c SDL_WINDOW_VULKAN flag. + /// + /// \code + /// unsigned int count; + /// // get count of required extensions + /// if(!SDL_Vulkan_GetInstanceExtensions(window, &count, NULL)) + /// handle_error(); + /// + /// static const char *const additionalExtensions[] = + /// { + /// VK_EXT_DEBUG_REPORT_EXTENSION_NAME, // example additional extension + /// }; + /// size_t additionalExtensionsCount = sizeof(additionalExtensions) / sizeof(additionalExtensions[0]); + /// size_t extensionCount = count + additionalExtensionsCount; + /// const char **names = malloc(sizeof(const char *) * extensionCount); + /// if(!names) + /// handle_error(); + /// + /// // get names of required extensions + /// if(!SDL_Vulkan_GetInstanceExtensions(window, &count, names)) + /// handle_error(); + /// + /// // copy additional extensions after required extensions + /// for(size_t i = 0; i < additionalExtensionsCount; i++) + /// names[i + count] = additionalExtensions[i]; + /// + /// VkInstanceCreateInfo instanceCreateInfo = {}; + /// instanceCreateInfo.enabledExtensionCount = extensionCount; + /// instanceCreateInfo.ppEnabledExtensionNames = names; + /// // fill in rest of instanceCreateInfo + /// + /// VkInstance instance; + /// // create the Vulkan instance + /// VkResult result = vkCreateInstance(&instanceCreateInfo, NULL, &instance); + /// free(names); + /// \endcode + /// + /// \sa SDL_Vulkan_CreateSurface() + pub fn SDL_Vulkan_GetInstanceExtensions( + window: *mut SDL_Window, + pCount: *mut ::std::os::raw::c_uint, + pNames: *mut *const ::std::os::raw::c_char, + ) -> SDL_bool; +} +extern "C" { + /// \brief Create a Vulkan rendering surface for a window. + /// + /// \param [in] window SDL_Window to which to attach the rendering surface. + /// \param [in] instance handle to the Vulkan instance to use. + /// \param [out] surface pointer to a VkSurfaceKHR handle to receive the + /// handle of the newly created surface. + /// + /// \return \c SDL_TRUE on success, \c SDL_FALSE on error. + /// + /// \code + /// VkInstance instance; + /// SDL_Window *window; + /// + /// // create instance and window + /// + /// // create the Vulkan surface + /// VkSurfaceKHR surface; + /// if(!SDL_Vulkan_CreateSurface(window, instance, &surface)) + /// handle_error(); + /// \endcode + /// + /// \note \a window should have been created with the \c SDL_WINDOW_VULKAN flag. + /// + /// \note \a instance should have been created with the extensions returned + /// by \c SDL_Vulkan_CreateSurface() enabled. + /// + /// \sa SDL_Vulkan_GetInstanceExtensions() + pub fn SDL_Vulkan_CreateSurface( + window: *mut SDL_Window, + instance: VkInstance, + surface: *mut VkSurfaceKHR, + ) -> SDL_bool; +} +extern "C" { + /// \brief Get the size of a window's underlying drawable in pixels (for use + /// with setting viewport, scissor & etc). + /// + /// \param window SDL_Window from which the drawable size should be queried + /// \param w Pointer to variable for storing the width in pixels, + /// may be NULL + /// \param h Pointer to variable for storing the height in pixels, + /// may be NULL + /// + /// This may differ from SDL_GetWindowSize() if we're rendering to a high-DPI + /// drawable, i.e. the window was created with SDL_WINDOW_ALLOW_HIGHDPI on a + /// platform with high-DPI support (Apple calls this "Retina"), and not disabled + /// by the \c SDL_HINT_VIDEO_HIGHDPI_DISABLED hint. + /// + /// \note On macOS high-DPI support must be enabled for an application by + /// setting NSHighResolutionCapable to true in its Info.plist. + /// + /// \sa SDL_GetWindowSize() + /// \sa SDL_CreateWindow() + pub fn SDL_Vulkan_GetDrawableSize( + window: *mut SDL_Window, + w: *mut ::std::os::raw::c_int, + h: *mut ::std::os::raw::c_int, + ); +} +///
+pub type VkInstance = usize; +///
+pub type VkSurfaceKHR = u64; pub type __builtin_va_list = [__va_list_tag; 1usize]; #[repr(C)] #[derive(Debug, Copy, Clone)] diff --git a/sdl2-sys/wrapper.h b/sdl2-sys/wrapper.h index ec2ef478..8412a434 100644 --- a/sdl2-sys/wrapper.h +++ b/sdl2-sys/wrapper.h @@ -1,2 +1,13 @@ #include #include +#include + +/** + *
+ */ +typedef uintptr_t VkInstance_int; + +/** + *
+ */ +typedef uint64_t VkSurfaceKHR_int; diff --git a/src/sdl2/audio.rs b/src/sdl2/audio.rs index c4bc2612..8af940f0 100644 --- a/src/sdl2/audio.rs +++ b/src/sdl2/audio.rs @@ -60,7 +60,6 @@ use std::ops::{Deref, DerefMut}; use std::path::Path; use std::marker::PhantomData; use std::mem; -use std::mem::transmute; use std::ptr; use AudioSubsystem; @@ -209,12 +208,16 @@ pub enum AudioStatus { impl FromPrimitive for AudioStatus { fn from_i64(n: i64) -> Option { use self::AudioStatus::*; - let n = n as u32; - Some( match unsafe { transmute::(n) } { - sys::SDL_AudioStatus::SDL_AUDIO_STOPPED => Stopped, - sys::SDL_AudioStatus::SDL_AUDIO_PLAYING => Playing, - sys::SDL_AudioStatus::SDL_AUDIO_PAUSED => Paused, + const STOPPED: i64 = sys::SDL_AudioStatus::SDL_AUDIO_STOPPED as i64; + const PLAYING: i64 = sys::SDL_AudioStatus::SDL_AUDIO_PLAYING as i64; + const PAUSED: i64 = sys::SDL_AudioStatus::SDL_AUDIO_PAUSED as i64; + + Some(match n { + STOPPED => Stopped, + PLAYING => Playing, + PAUSED => Paused, + _ => return None, }) } @@ -373,13 +376,15 @@ extern "C" fn audio_callback_marshall use std::slice::from_raw_parts_mut; use std::mem::size_of; unsafe { - let cb_userdata: &mut CB = &mut *(userdata as *mut CB); + let cb_userdata: &mut Option = &mut *(userdata as *mut _); let buf: &mut [CB::Channel] = from_raw_parts_mut( stream as *mut CB::Channel, len as usize / size_of::() ); - cb_userdata.callback(buf); + if let Some(cb) = cb_userdata { + cb.callback(buf); + } } } @@ -394,14 +399,13 @@ pub struct AudioSpecDesired { } impl AudioSpecDesired { - fn convert_to_ll(freq: F, channels: C, samples: S, userdata: *mut CB) -> sys::SDL_AudioSpec + fn convert_to_ll(freq: F, channels: C, samples: S, userdata: *mut Option) -> sys::SDL_AudioSpec where CB: AudioCallback, F: Into>, C: Into>, S: Into>, { - use std::mem::transmute; let freq = freq.into(); let channels = channels.into(); @@ -413,22 +417,20 @@ impl AudioSpecDesired { // A value of 0 means "fallback" or "default". - unsafe { - sys::SDL_AudioSpec { - freq: freq.unwrap_or(0), - format: ::audio_format().to_ll(), - channels: channels.unwrap_or(0), - silence: 0, - samples: samples.unwrap_or(0), - padding: 0, - size: 0, - callback: Some(audio_callback_marshall:: - as extern "C" fn - (arg1: *mut c_void, - arg2: *mut uint8_t, - arg3: c_int)), - userdata: transmute(userdata) - } + sys::SDL_AudioSpec { + freq: freq.unwrap_or(0), + format: ::audio_format().to_ll(), + channels: channels.unwrap_or(0), + silence: 0, + samples: samples.unwrap_or(0), + padding: 0, + size: 0, + callback: Some(audio_callback_marshall:: + as extern "C" fn + (arg1: *mut c_void, + arg2: *mut uint8_t, + arg3: c_int)), + userdata: userdata as *mut _, } } @@ -596,7 +598,7 @@ pub struct AudioDevice { device_id: AudioDeviceID, spec: AudioSpec, /// Store the callback to keep it alive for the entire duration of `AudioDevice`. - userdata: Box + userdata: Box> } impl AudioDevice { @@ -607,14 +609,8 @@ impl AudioDevice { D: Into>, { - // SDL_OpenAudioDevice needs a userdata pointer, but we can't initialize the - // callback without the obtained AudioSpec. - // Create an uninitialized box that will be initialized after SDL_OpenAudioDevice. - let userdata: *mut CB = unsafe { - let b: Box = Box::new(mem::uninitialized()); - mem::transmute(b) - }; - let desired = AudioSpecDesired::convert_to_ll(spec.freq, spec.channels, spec.samples, userdata); + let mut userdata: Box> = Box::new(None); + let desired = AudioSpecDesired::convert_to_ll(spec.freq, spec.channels, spec.samples, &mut *userdata); let mut obtained = unsafe { mem::uninitialized::() }; unsafe { @@ -636,10 +632,8 @@ impl AudioDevice { id => { let device_id = AudioDeviceID::PlaybackDevice(id); let spec = AudioSpec::convert_from_ll(obtained); - let mut userdata: Box = mem::transmute(userdata); - let garbage = mem::replace(&mut userdata as &mut CB, get_callback(spec)); - mem::forget(garbage); + *userdata = Some(get_callback(spec)); Ok(AudioDevice { subsystem: a.clone(), @@ -713,7 +707,7 @@ impl AudioDevice { /// but the callback data will be dropped. pub fn close_and_get_callback(self) -> CB { drop(self.device_id); - *self.userdata + self.userdata.expect("Missing callback") } } @@ -725,11 +719,11 @@ pub struct AudioDeviceLockGuard<'a, CB> where CB: AudioCallback, CB: 'a { impl<'a, CB: AudioCallback> Deref for AudioDeviceLockGuard<'a, CB> { type Target = CB; - fn deref(&self) -> &CB { &self.device.userdata } + fn deref(&self) -> &CB { (*self.device.userdata).as_ref().expect("Missing callback") } } impl<'a, CB: AudioCallback> DerefMut for AudioDeviceLockGuard<'a, CB> { - fn deref_mut(&mut self) -> &mut CB { &mut self.device.userdata } + fn deref_mut(&mut self) -> &mut CB { (*self.device.userdata).as_mut().expect("Missing callback") } } impl<'a, CB: AudioCallback> Drop for AudioDeviceLockGuard<'a, CB> { @@ -829,13 +823,13 @@ mod test { assert!(cvt.is_conversion_needed()); // since we're going from mono to stereo, our capacity must be at least twice the original (255) vec size - assert!(cvt.capacity(255) > 255*2, "capacity must be able to hold the converted audio sample"); + assert!(cvt.capacity(255) >= 255*2, "capacity must be able to hold the converted audio sample"); let new_buffer = cvt.convert(buffer); assert_eq!(new_buffer.len(), new_buffer_expected.len(), "capacity must be exactly equal to twice the original vec size"); // // this has been commented, see https://discourse.libsdl.org/t/change-of-behavior-in-audiocvt-sdl-convertaudio-from-2-0-5-to-2-0-6/24682 - // // to maybe re-enable it someday + // // to maybe re-enable it someday // assert_eq!(new_buffer, new_buffer_expected); } } diff --git a/src/sdl2/common.rs b/src/sdl2/common.rs index 88a73dae..7eeae915 100644 --- a/src/sdl2/common.rs +++ b/src/sdl2/common.rs @@ -3,7 +3,7 @@ use std::fmt; /// A given integer was so big that its representation as a C integer would be /// negative. -#[derive(Debug)] +#[derive(Debug, Clone, PartialEq)] pub enum IntegerOrSdlError { IntegerOverflows(&'static str, u32), SdlError(String) diff --git a/src/sdl2/controller.rs b/src/sdl2/controller.rs index f3825762..9974e8a8 100644 --- a/src/sdl2/controller.rs +++ b/src/sdl2/controller.rs @@ -2,6 +2,7 @@ use libc::c_char; use std::error; use std::ffi::{CString, CStr, NulError}; use std::fmt; +use std::io; use std::path::Path; use rwops::RWops; @@ -17,6 +18,7 @@ use sys; pub enum AddMappingError { InvalidMapping(NulError), InvalidFilePath(String), + ReadError(String), SdlError(String), } @@ -27,7 +29,8 @@ impl fmt::Display for AddMappingError { match *self { InvalidMapping(ref e) => write!(f, "Null error: {}", e), InvalidFilePath(ref value) => write!(f, "Invalid file path ({})", value), - SdlError(ref e) => write!(f, "SDL error: {}", e) + ReadError(ref e) => write!(f, "Read error: {}", e), + SdlError(ref e) => write!(f, "SDL error: {}", e), } } } @@ -39,6 +42,7 @@ impl error::Error for AddMappingError { match *self { InvalidMapping(_) => "invalid mapping", InvalidFilePath(_) => "invalid file path", + ReadError(_) => "read error", SdlError(ref e) => e, } } @@ -110,7 +114,7 @@ impl GameControllerSubsystem { == sys::SDL_ENABLE as i32 } } - /// Add a new mapping from a mapping string + /// Add a new controller input mapping from a mapping string. pub fn add_mapping(&self, mapping: &str) -> Result { use self::AddMappingError::*; @@ -128,24 +132,36 @@ impl GameControllerSubsystem { } } - /// Load mappings from a file - pub fn load_mappings>(&self, path: P) - -> Result { + /// Load controller input mappings from a file. + pub fn load_mappings>(&self, path: P) -> Result { use self::AddMappingError::*; - let file = match RWops::from_file(path, "r") { - Ok(f) => f, - Err(s) => return Err(InvalidFilePath(s)) - }; - - let result = unsafe { sys::SDL_GameControllerAddMappingsFromRW(file.raw(), 0) }; - - match result { - -1 => Err(SdlError(get_error())), - _ => Ok(result) - } + let rw = RWops::from_file(path, "r").map_err(InvalidFilePath)?; + self.load_mappings_from_rw(rw) } + /// Load controller input mappings from a [`Read`](std::io::Read) object. + pub fn load_mappings_from_read( + &self, + read: &mut R, + ) -> Result { + use self::AddMappingError::*; + + let mut buffer = Vec::with_capacity(1024); + let rw = RWops::from_read(read, &mut buffer).map_err(ReadError)?; + self.load_mappings_from_rw(rw) + } + + /// Load controller input mappings from an SDL [`RWops`] object. + pub fn load_mappings_from_rw<'a>(&self, rw: RWops<'a>) -> Result { + use self::AddMappingError::*; + + let result = unsafe { sys::SDL_GameControllerAddMappingsFromRW(rw.raw(), 0) }; + match result { + -1 => Err(SdlError(get_error())), + _ => Ok(result), + } + } pub fn mapping_for_guid(&self, guid: joystick::Guid) -> Result { let c_str = unsafe { sys::SDL_GameControllerMappingForGUID(guid.raw()) }; diff --git a/src/sdl2/lib.rs b/src/sdl2/lib.rs index 69f58976..83deb0a5 100644 --- a/src/sdl2/lib.rs +++ b/src/sdl2/lib.rs @@ -1,6 +1,8 @@ //! # Getting started //! //! ```rust,no_run +//! extern crate sdl2; +//! //! use sdl2::pixels::Color; //! use sdl2::event::Event; //! use sdl2::keyboard::Keycode; diff --git a/src/sdl2/video.rs b/src/sdl2/video.rs index cd314fb9..20cd7f5f 100644 --- a/src/sdl2/video.rs +++ b/src/sdl2/video.rs @@ -1,4 +1,4 @@ -use libc::{c_int, c_float, uint32_t, c_char}; +use libc::{c_int, c_uint, c_float, uint32_t, c_char}; use std::ffi::{CStr, CString, NulError}; use std::{mem, ptr, fmt}; use std::rc::Rc; @@ -18,6 +18,8 @@ use get_error; use sys; +pub use sys::{VkInstance, VkSurfaceKHR}; + pub struct WindowSurfaceRef<'a>(&'a mut SurfaceRef, &'a Window); @@ -807,6 +809,61 @@ impl VideoSubsystem { mem::transmute(interval) } } + + /// Loads the default Vulkan library. + /// + /// This should be done after initializing the video driver, but before creating any Vulkan windows. + /// If no Vulkan library is loaded, the default library will be loaded upon creation of the first Vulkan window. + /// + /// If a different library is already loaded, this function will return an error. + pub fn vulkan_load_library_default(&self) -> Result<(), String> { + unsafe { + if sys::SDL_Vulkan_LoadLibrary(ptr::null()) == 0 { + Ok(()) + } else { + Err(get_error()) + } + } + } + + /// Loads the Vulkan library using a platform-dependent Vulkan library name (usually a file path). + /// + /// This should be done after initializing the video driver, but before creating any Vulkan windows. + /// If no Vulkan library is loaded, the default library will be loaded upon creation of the first Vulkan window. + /// + /// If a different library is already loaded, this function will return an error. + pub fn vulkan_load_library>(&self, path: P) -> Result<(), String> { + unsafe { + // TODO: use OsStr::to_cstring() once it's stable + let path = CString::new(path.as_ref().to_str().unwrap()).unwrap(); + if sys::SDL_Vulkan_LoadLibrary(path.as_ptr() as *const c_char) == 0 { + Ok(()) + } else { + Err(get_error()) + } + } + } + + /// Unloads the current Vulkan library. + /// + /// To completely unload the library, this should be called for every successful load of the + /// Vulkan library. + pub fn vulkan_unload_library(&self) { + unsafe { sys::SDL_Vulkan_UnloadLibrary(); } + } + + /// Gets the pointer to the + /// [`vkGetInstanceProcAddr`](https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkGetInstanceProcAddr.html) + /// Vulkan function. This function can be called to retrieve the address of other Vulkan + /// functions. + pub fn vulkan_get_proc_address_function(&self) -> Result<*const (), String> { + let result = unsafe { sys::SDL_Vulkan_GetVkGetInstanceProcAddr() as *const () }; + if result.is_null() { + Err(get_error()) + } else { + Ok(result) + } + } } #[derive(Debug)] @@ -1070,6 +1127,33 @@ impl Window { unsafe { sys::SDL_GL_SwapWindow(self.context.raw) } } + /// Get the names of the Vulkan instance extensions needed to create a surface with `vulkan_create_surface`. + pub fn vulkan_instance_extensions(&self) -> Result, String> { + let mut count: c_uint = 0; + if unsafe { sys::SDL_Vulkan_GetInstanceExtensions(self.context.raw, &mut count, ptr::null_mut()) } == sys::SDL_bool::SDL_FALSE { + return Err(get_error()); + } + let mut names: Vec<*const c_char> = vec![ptr::null(); count as usize]; + if unsafe { sys::SDL_Vulkan_GetInstanceExtensions(self.context.raw, &mut count, names.as_mut_ptr()) } == sys::SDL_bool::SDL_FALSE { + return Err(get_error()); + } + Ok(names.iter().map(|&val| unsafe { CStr::from_ptr(val) }.to_str().unwrap()).collect()) + } + + /// Create a Vulkan rendering surface for a window. + /// + /// The `VkInstance` must be created using a prior call to the + /// [`vkCreateInstance`](https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkCreateInstance.html) + /// function in the Vulkan library. + pub fn vulkan_create_surface(&self, instance: VkInstance) -> Result { + let mut surface: VkSurfaceKHR = 0; + if unsafe { sys::SDL_Vulkan_CreateSurface(self.context.raw, instance, &mut surface) } == sys::SDL_bool::SDL_FALSE { + Err(get_error()) + } else { + Ok(surface) + } + } + pub fn display_index(&self) -> Result { let result = unsafe { sys::SDL_GetWindowDisplayIndex(self.context.raw) }; if result < 0 { @@ -1205,6 +1289,13 @@ impl Window { (w as u32, h as u32) } + pub fn vulkan_drawable_size(&self) -> (u32, u32) { + let mut w: c_int = 0; + let mut h: c_int = 0; + unsafe { sys::SDL_Vulkan_GetDrawableSize(self.context.raw, &mut w, &mut h) }; + (w as u32, h as u32) + } + pub fn set_minimum_size(&mut self, width: u32, height: u32) -> Result<(), IntegerOrSdlError> { let w = try!(validate_int(width, "width"));