使用旧的Rust 2015
0.32.2 |
|
---|
#42 in #sdl
680KB
12K SLoC
Rust-SDL2

SDL2在Rust中的绑定
0.32版本变更日志
概述
Rust-SDL2是一个用于与Rust中的新SDL2.0库进行通信的库。使用Rust代码封装底层C组件,使其更加符合惯例,并抽象出不适用的手动内存管理。
Rust-SDL2使用MIT许可证。
如果您需要一个与SDL早期版本兼容的库,请参阅此处
文档
- crates.io文档,没有任何功能。
- 主文档具有以下功能
- gfx
- image
- mixer
- ttf
需求
Rust
我们目前针对Rust的最新稳定版。
SDL2.0开发库
建议使用SDL2 >= 2.0.8绑定这些库,但请注意,也支持SDL2 >= 2.0.5。如果低于2.0.5,您可能会遇到链接时错误,因为这里使用了某些函数,但它们在SDL2中未定义。如果您因为使用LTS机器(例如,Ubuntu 12.04或Ubuntu 14.04)而遇到此问题,我们强烈建议您使用“bundled”功能,该功能将为您的项目编译最新的稳定版SDL2。
“Bundled”功能
从0.31版开始,此crate支持一个名为“bundled”的功能,该功能从源代码下载SDL2,自动编译并链接。虽然这应该适用于任何架构,但您必须使用C编译器(如gcc
、clang
或MS的编译器)才能正确使用此功能。
Linux
通过您喜欢的包管理工具安装这些程序,或者通过http://www.libsdl.org/
Ubuntu 示例
sudo apt-get install libsdl2-dev
Fedora 示例
sudo dnf install SDL2-devel
Arch 示例
(Arch 没有分开的常规和开发包,所有内容都是一起的。)
sudo pacman -S sdl2
您可能还需要一个C编译器(gcc)。
Mac OS X
如果您使用homebrew
在OSX上,通过homebrew安装这些是个好主意。
brew install sdl2
然后,如果您还没有这样做,请将以下内容添加到您的~/.bash_profile
文件中。
export LIBRARY_PATH="$LIBRARY_PATH:/usr/local/lib"
否则,如果您使用macports
您也可以通过macports
获取sdl2。
sudo port install libsdl2
然后,如果您还没有这样做,请将以下内容添加到您的~/.bash_profile
文件中。
export LIBRARY_PATH="$LIBRARY_PATH:/opt/local/lib/"
如果您在homebrew或macports上遇到问题,请查看这里。
如果您使用SDL2框架
您可以从https://www.libsdl.org/download-2.0.php下载并安装SDL2 Mac OS X框架。
要使sdl2
crate链接到SDL2框架,您需要启用use_mac_framework
功能。要使用此功能构建和测试sdl2
crate,请使用
cargo test --features use_mac_framework
要启用此功能并依赖sdl2
crate,请将以下内容放入您的项目的Cargo.toml
文件中
[dependencies.sdl2]
features = ["use_mac_framework"]
version = ... # Whichever version you are using
或者,您可以通过在Cargo.toml
文件中放置以下内容来在您的包中重新导出此功能
[features]
default = []
use_sdl2_mac_framework = ["sdl2/use_mac_framework"]
带有构建脚本的Windows
- 从http://www.libsdl.org/下载mingw和msvc开发库(SDL2-devel-2.0.x-mingw.tar.gz & SDL2-devel-2.0.x-VC.zip)。
- 解压到您选择的文件夹(之后可以删除)。
- 在Cargo.toml相同的文件夹中创建以下文件夹结构
gnu-mingw\dll\32
gnu-mingw\dll\64
gnu-mingw\lib\32
gnu-mingw\lib\64
msvc\dll\32
msvc\dll\64
msvc\lib\32
msvc\lib\64
- 将源存档中的lib和dll文件复制到我们在步骤3中创建的目录中,如下所示
SDL2-devel-2.0.x-mingw.tar.gz\SDL2-2.0.x\i686-w64-mingw32\bin -> gnu-mingw\dll\32
SDL2-devel-2.0.x-mingw.tar.gz\SDL2-2.0.x\x86_64-w64-mingw32\bin -> gnu-mingw\dll\64
SDL2-devel-2.0.x-mingw.tar.gz\SDL2-2.0.x\i686-w64-mingw32\lib -> gnu-mingw\lib\32
SDL2-devel-2.0.x-mingw.tar.gz\SDL2-2.0.x\x86_64-w64-mingw32\lib -> gnu-mingw\lib\64
SDL2-devel-2.0.8-VC.zip\SDL2-2.0.x\lib\x86\*.dll -> msvc\dll\32
SDL2-devel-2.0.8-VC.zip\SDL2-2.0.x\lib\x64\*.dll -> msvc\dll\64
SDL2-devel-2.0.8-VC.zip\SDL2-2.0.x\lib\x86\*.lib -> msvc\lib\32
SDL2-devel-2.0.8-VC.zip\SDL2-2.0.x\lib\x64\*.lib -> msvc\lib\64
- 如果您还没有构建脚本,请在Cargo.toml中的以下位置创建一个build脚本
build = "build.rs"
- 在Cargo.toml相同的目录中创建一个名为build.rs的文件(如果您还没有构建脚本)并将以下内容粘贴到其中
use std::env;
use std::path::PathBuf;
fn main() {
let target = env::var("TARGET").unwrap();
if target.contains("pc-windows") {
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let mut lib_dir = manifest_dir.clone();
let mut dll_dir = manifest_dir.clone();
if target.contains("msvc") {
lib_dir.push("msvc");
dll_dir.push("msvc");
}
else {
lib_dir.push("gnu-mingw");
dll_dir.push("gnu-mingw");
}
lib_dir.push("lib");
dll_dir.push("dll");
if target.contains("x86_64") {
lib_dir.push("64");
dll_dir.push("64");
}
else {
lib_dir.push("32");
dll_dir.push("32");
}
println!("cargo:rustc-link-search=all={}", lib_dir.display());
for entry in std::fs::read_dir(dll_dir).expect("Can't read DLL dir") {
let entry_path = entry.expect("Invalid fs entry").path();
let file_name_result = entry_path.file_name();
let mut new_file_path = manifest_dir.clone();
if let Some(file_name) = file_name_result {
let file_name = file_name.to_str().unwrap();
if file_name.ends_with(".dll") {
new_file_path.push(file_name);
std::fs::copy(&entry_path, new_file_path.as_path()).expect("Can't copy from DLL dir");
}
}
}
}
}
- 在构建时,构建脚本将所需DLL复制到与Cargo.toml相同的目录,但您可能不希望将这些文件提交到任何Git仓库,因此请向您的.gitignore文件添加以下行
/*.dll
- 当您发布游戏时,请确保将相应的SDL2.dll复制到与编译后的exe相同的目录,否则游戏无法启动。
现在,您的项目应该可以在任何Windows计算机上构建和运行了!
Windows(MinGW)
-
从http://www.libsdl.org/下载mingw开发库(SDL2-devel-2.0.x-mingw.tar.gz)。
-
解压到您选择的文件夹(之后可以删除)。
-
将以下目录中的所有lib文件复制到
SDL2-devel-2.0.x-mingw\SDL2-2.0.x\x86_64-w64-mingw32\lib
到(对于Rust 1.6及以上版本)
C:\Program Files\Rust\lib\rustlib\x86_64-pc-windows-gnu\lib
或者(对于Rust版本1.5及以下)
C:\Program Files\Rust\bin\rustlib\x86_64-pc-windows-gnu\lib
或者到您选择的库文件夹,并确保您有一个系统环境变量
LIBRARY_PATH = C:\your\rust\library\folder
对于Rustup用户,此文件夹位于
C:\Users\{Your Username}\.rustup\toolchains\{current toolchain}\lib\rustlib\{current toolchain}\lib
其中current toolchain可能是stable-x86_64-pc-windows-gnu
。
-
从
SDL2-devel-2.0.x-mingw\SDL2-2.0.x\x86_64-w64-mingw32\bin
将其添加到您的Cargo项目中,紧挨着您的Cargo.toml文件。
-
当您发布游戏时,请确保将SDL2.dll复制到与编译后的exe文件相同的目录中,否则游戏无法启动。
使用MinGW进行静态链接
如果您想使用windows-gnu工具链的static-link
功能,那么您还需要以下库
libimm32.a
libversion.a
libdinput8.a
libdxguid.a
这些文件目前不包含在windows-gnu工具链中,但可以从这里下载。对于x86_64工具链,您需要的是x86_64-win32-seh
包,对于i686,您需要的是i686-win32-dwarf
包。
您可以在mingw64/x86_64-w64-mingw32/lib/
(对于x86_64)或mingw32/i686-w64-mingw32/lib/
(对于i686)下找到上述库。将它们复制到您的工具链的lib
目录中(与您复制SDL .a文件相同的目录)。
Windows (MSVC)
-
从http://www.libsdl.org/下载MSVC开发库(SDL2-devel-2.0.x-VC.zip)。
-
将SDL2-devel-2.0.x-VC.zip解压缩到您选择的文件夹中(之后您可以删除它)。
-
将以下目录中的所有lib文件复制到
SDL2-devel-2.0.x-VC\SDL2-2.0.x\lib\x64\
到(对于Rust 1.6及以上版本)
C:\Program Files\Rust\lib\rustlib\x86_64-pc-windows-msvc\lib
或者(对于Rust版本1.5及以下)
C:\Program Files\Rust\bin\rustlib\x86_64-pc-windows-msvc\lib
或者到您选择的库文件夹,并确保您有一个系统环境变量
LIB = C:\your\rust\library\folder
对于Rustup用户,此文件夹位于
C:\Users\{Your Username}\.rustup\toolchains\{current toolchain}\lib\rustlib\{current toolchain}\lib
当前工具链可能是stable-x86_64-pc-windows-msvc
。
-
从
SDL2-devel-2.0.x-VC\SDL2-2.0.x\lib\x64\
将其添加到您的Cargo项目中,紧挨着您的Cargo.toml文件。
-
当您发布游戏时,请确保将SDL2.dll复制到与编译后的exe文件相同的目录中,否则游戏无法启动。
使用MSVC进行静态链接
从http://libsdl.org/提供的MSVC开发库不包含静态库。这意味着如果您想使用windows-msvc工具链的static-link
功能,您必须
- 自己构建SDL2静态库并将其复制到工具链的
lib
目录中;或者 - 同时启用
bundled
功能,该功能将为您构建静态库。
安装
如果您使用cargo管理项目,您可以通过Crates.io下载
[dependencies]
sdl2 = "0.32"
或者,从GitHub拉取以获取master的最新版本
[dependencies.sdl2]
git = "https://github.com/AngryLawyer/rust-sdl2"
否则,克隆此仓库并运行cargo
cargo build
您可以通过添加以下内容来启用功能,例如ttf、image、gfx和mixer
[dependencies.sdl2]
version = "0.32"
default-features = false
features = ["ttf","image","gfx","mixer"]
这些功能需要相应的库,可以在以下位置找到:(安装过程与SDL2相同)
关于sdl2_net呢?
到目前为止,与如serde
和bincode
等其他crate相比,sdl2_net没有意义。我们强烈建议使用它们来开发任何UDP或TCP相关的内容(同时使用futures或标准库中的TCP/UDP)。
如果您仍然想添加sdl2_net的实现,您可以通过Pull Request将它们添加到这个仓库中作为功能。这个绑定的一个相对较旧的版本可以在这里找到
演示
我们包含了一些简单的示例项目
cargo run --example demo
您可以在examples/
文件夹中查看完整的列表。一些示例需要某些功能,您可以通过以下方式启用它们
cargo run --example gfx-demo --features "gfx"
将"gfx"替换为您想要的示例所需的功能。
关于unsafe_textures
功能
在 sdl2::render
模块中,Texture
默认具有生命周期,以防止其生命周期超过其父 TextureCreator
。这些生命周期在 Rust 中有时很难处理,因此您可以选择启用 unsafe_textures
功能。
这会移除 Texture
上的生命周期,但代价是可选的手动内存管理。如果您想手动销毁您使用的 Texture
,可以调用您的 Texture
的 destroy
方法,但请注意,不应该 在父项(Canvas
或 TextureCreator
)都存活的情况下调用该方法。如果您不调用此方法,内存将在最后一个 Canvas
或最后一个 TextureCreator
被释放时自动释放。
此功能没有在线文档,但是您可以通过在 Cargo.toml 中启用功能、运行 cargo doc
并通过浏览器访问 target/doc/sdl2/index.html
来在自己的项目中构建它。
使用 bindgen 生成 sdl2-sys
为此 crate 生成的是非常通用的 sdl2-sys,可以用于许多平台,限制很少。然而,您有时在使用 SDL2 的特定平台功能时可能会遇到麻烦,例如窗口管理器类别。
"use-bindgen" 功能允许您通过根据您的目标生成适当的绑定来避免这种限制。它将根据 pkg-config
输出的内容(如果您启用了 "use-pkg-config" 功能)获取头文件,并基于这些头文件生成绑定。如果您没有 pkg-config 或禁用了该功能,它将尝试从此 crate 的 SDL-2.0.8/include
中获取头文件。
如果您有自己的头文件想使用(使用 beta 版本、旧版本等),可以设置环境变量 "SDL2_INCLUDE_PATH",然后 bindgen 将使用这些头文件。
OpenGL
如果您想使用 OpenGL,还需要 gl-rs 包。如果您使用 cargo,只需将以下行添加到您的 Cargo.toml 中
[dependencies.gl]
git = "https://github.com/bjz/gl-rs"
使用 OpenGL 的两种方式
- 使用 Canvas 和 sdl2::render 一起使用 OpenGL
- 直接在 "shell" 窗口上使用 OpenGL 并使用手动 OpenGL 调用来渲染内容
使用 sdl2::render
首先,从 SDL 中找到 OpenGL 驱动程序
fn find_sdl_gl_driver() -> Option<u32> {
for (index, item) in sdl2::render::drivers().enumerate() {
if item.name == "opengl" {
return Some(index as u32);
}
}
None
}
这在非 Linux 系统上尤其相关,因为在这些系统中,默认的渲染引擎可能是其他引擎(例如 Windows 上的 DirectX)。
接下来,初始化 SDL2 子系统,并使用 OpenGL 画布创建您的窗口
let sdl_context = sdl2::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
let window = video_subsystem.window("Window", 800, 600)
.opengl()
.build()
.unwrap();
let canvas = window.into_canvas()
.index(find_sdl_gl_driver().unwrap())
.build()
.unwrap();
gl::load_with(|name| video_subsystem.gl_get_proc_address(name) as *const _);
canvas.window().gl_set_context_to_current();
unsafe {
gl::ClearColor(0.6, 0.0, 0.8, 1.0);
gl::Clear(gl::COLOR_BUFFER_BIT);
}
canvas.present();
// opengl code here
但是请注意,sdl2 有自己的内部状态,您应该避免干预。避免在 SDL2 调用中间使用手动 OpenGL,或在此之间更改状态。
您无法通过这种方法覆盖 OpenGL 版本,除非通过更改 gl 状态
手动使用 OpenGL 调用
extern crate sdl2;
extern crate gl;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::video::GLProfile;
fn main() {
let sdl_context = sdl2::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
let gl_attr = video_subsystem.gl_attr();
gl_attr.set_context_profile(GLProfile::Core);
gl_attr.set_context_version(3, 3);
let window = video_subsystem.window("Window", 800, 600)
.opengl()
.build()
.unwrap();
let ctx = window.gl_create_context().unwrap();
gl::load_with(|name| video_subsystem.gl_get_proc_address(name) as *const _);
debug_assert_eq!(gl_attr.context_profile(), GLProfile::Core);
debug_assert_eq!(gl_attr.context_version(), (3, 3));
let mut event_pump = sdl_context.event_pump().unwrap();
'running: loop {
unsafe {
gl::ClearColor(0.6, 0.0, 0.8, 1.0);
gl::Clear(gl::COLOR_BUFFER_BIT);
}
window.gl_swap_window();
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));
}
}
当您不关心 sdl2 的渲染功能,但关心其音频、控制器和其他一些 cool 功能时,这种方法很有用。
Vulkan
要使用 Vulkan,您需要一个 Rust 的 Vulkan 库。此示例使用 Vulkano 库。其他库可能使用不同的原始 Vulkan 对象句柄数据类型。与这些库接口 SDL2 的 Vulkan 函数的步骤将因每个库而异。
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));
}
}
当事情出错时
Rust 和 Rust-SDL2 都还在积极开发中,使用时可能会遇到一些成长问题。在恐慌之前,请检查您是否正在使用 Rust 和 Cargo 的最新版本,并确保您已将 Rust-SDL2 更新到最新版本。然后运行 cargo clean
。如果这失败了,请通过问题跟踪器告诉我们。
贡献
欢迎任何大小的 Pull Request!然而,贡献也有一些条件。
- 新功能必须有适当的文档,无论是通过示例还是内联文档(通过
cargo doc
)。文档必须面向最终用户以及您的下一位贡献者。 - 重大更改必须附有适当的论证。虽然这个 crate 的 1.0 版本之前的版本允许我们保持一定的不稳定,但 无用的重大更改将被拒绝。
- 通过 Pull Request 添加的次要更改、重大更改和新功能必须添加到 变更日志文件。现在,在变更日志中记录您的更改是 强制性的。一个简短的描述以及指向您的 GitHub 提交/拉取请求的链接即可。内部、文档或元更改(travis 构建更改、README 指令更新等)无需添加到变更日志中。
依赖项
~17MB
~351K SLoC