Compare commits

..

1 commit

Author SHA1 Message Date
cf1549a45b Update Rust crate ron to 0.9.0 2025-03-24 15:02:10 +00:00
11 changed files with 250 additions and 117 deletions

View file

@ -49,7 +49,7 @@ hostname = { version = "0.4.0" }
trust-dns-resolver = { version = "0.23.2" }
openxr = { version = "0.19.0", default-features = false, features = ["static"] }
openvr = { version = "0.7.0" }
sdl3 = { version = "0.14.19" }
sdl2 = { version = "0.37.0" }
syn = { version = "2.0.67", features = ["extra-traits", "full"] }
quote = "1.0.35"
proc-macro2 = "1.0.86"

View file

@ -1,3 +1,4 @@
use crate::prelude::*;
use presentation::wsi::windowsystemintegration::WindowSystemIntegration;
use anyhow::Result;
@ -58,6 +59,10 @@ impl<'a> WindowConfig<'a> {
Ok(())
}
pub fn displays(&self) -> &[Display] {
self.wsi.displays()
}
pub fn clipboard_content(&self) -> Result<Option<String>> {
self.wsi.clipboard_content()
}

View file

@ -236,6 +236,7 @@ impl Default for ContextBuilder {
width: 800,
height: 600,
fullscreen: false,
requested_display: None,
},
// os specifics
@ -424,6 +425,14 @@ impl ContextBuilder {
presentation.event_system_mut().enable_mouse();
}
if self.enable_keyboard {
presentation.event_system_mut().enable_keyboard();
}
if self.enable_controller {
presentation.event_system_mut().enable_controller();
}
Ok(Context {
core,
presentation,

View file

@ -48,6 +48,7 @@ impl<'a> Default for EngineCreateInfo<'a> {
width: 1600,
height: 900,
fullscreen: false,
requested_display: None,
},
os_specific_config: OsSpecificConfig {
enable_game_mode: true,

View file

@ -7,7 +7,7 @@ edition = "2024"
[dependencies]
vulkan-rs = { workspace = true }
ui = { workspace = true }
sdl3 = { workspace = true }
sdl2 = { workspace = true }
anyhow = { workspace = true }
openxr = { workspace = true, optional = true }
@ -18,5 +18,5 @@ ecs = { workspace = true }
[features]
OpenXR = ["openxr"]
OpenVR = ["openvr"]
BundleSDL = ["sdl3/build-from-source-static"]
BundleSDL = ["sdl2/bundled", "sdl2/static-link"]
sound = ["ui/audio"]

View file

@ -3,7 +3,7 @@ use ui::prelude::*;
use super::controlleraxis::ControllerAxis;
use sdl3::{self, GamepadSubsystem};
use sdl2::{self, GameControllerSubsystem};
#[derive(PartialEq)]
enum State {
@ -32,7 +32,7 @@ impl Default for ControllerDeadzones {
}
pub struct Controller {
_sdl2_controller: sdl3::gamepad::Gamepad,
_sdl2_controller: sdl2::controller::GameController,
name: String,
id: u32,
@ -51,7 +51,7 @@ pub struct Controller {
impl Controller {
pub fn new(
controller_subsystem: &GamepadSubsystem,
controller_subsystem: &GameControllerSubsystem,
id: u32,
deadzones: ControllerDeadzones,
) -> Result<Controller> {

View file

@ -1,27 +1,30 @@
use sdl3::{
self, EventPump, EventSubsystem, GamepadSubsystem, JoystickSubsystem, Sdl,
event::{Event as SdlEvent, WindowEvent},
gamepad::{Axis, Button},
keyboard::Keycode,
mouse::{MouseButton as SdlMouseButton, MouseUtil, MouseWheelDirection},
};
use sdl2;
use sdl2::EventPump;
use sdl2::EventSubsystem;
use sdl2::GameControllerSubsystem;
use sdl2::JoystickSubsystem;
use sdl2::Sdl;
use sdl2::controller::Axis;
use sdl2::controller::Button;
use sdl2::event::{Event as SdlEvent, EventType as SdlEventType, WindowEvent};
use sdl2::keyboard::Keycode;
use sdl2::mouse::{MouseButton as SdlMouseButton, MouseUtil, MouseWheelDirection};
use ui::prelude::*;
use std::collections::HashMap;
use crate::Result;
use anyhow::anyhow;
use super::controller::{Controller, ControllerDeadzones};
use super::joystick::Joystick;
fn convert_button(button: Button) -> ControllerButton {
match button {
Button::South => ControllerButton::A,
Button::East => ControllerButton::B,
Button::North => ControllerButton::Y,
Button::West => ControllerButton::X,
Button::A => ControllerButton::A,
Button::B => ControllerButton::B,
Button::Y => ControllerButton::Y,
Button::X => ControllerButton::X,
Button::Start => ControllerButton::Start,
Button::Back => ControllerButton::Select,
@ -41,10 +44,10 @@ fn convert_button(button: Button) -> ControllerButton {
Button::Misc1 => ControllerButton::Misc,
Button::RightPaddle1 => ControllerButton::Paddle1,
Button::RightPaddle2 => ControllerButton::Paddle2,
Button::LeftPaddle1 => ControllerButton::Paddle3,
Button::LeftPaddle2 => ControllerButton::Paddle4,
Button::Paddle1 => ControllerButton::Paddle1,
Button::Paddle2 => ControllerButton::Paddle2,
Button::Paddle3 => ControllerButton::Paddle3,
Button::Paddle4 => ControllerButton::Paddle4,
Button::Touchpad => ControllerButton::Touchpad,
}
@ -84,7 +87,7 @@ pub enum Event<'a> {
pub struct EventSystem {
event_pump: EventPump,
mouse: MouseUtil,
controller_subsystem: GamepadSubsystem,
controller_subsystem: GameControllerSubsystem,
joystick_subsystem: JoystickSubsystem,
event_subsystem: EventSubsystem,
@ -101,7 +104,9 @@ impl EventSystem {
.event_pump()
.map_err(|s| anyhow::Error::msg(s))?,
mouse: sdl2_context.mouse(),
controller_subsystem: sdl2_context.gamepad().map_err(|s| anyhow::Error::msg(s))?,
controller_subsystem: sdl2_context
.game_controller()
.map_err(|s| anyhow::Error::msg(s))?,
joystick_subsystem: sdl2_context.joystick().map_err(|s| anyhow::Error::msg(s))?,
event_subsystem: sdl2_context.event().map_err(|s| anyhow::Error::msg(s))?,
@ -111,22 +116,17 @@ impl EventSystem {
connected_joysticks: HashMap::new(),
};
event_system.connected_joysticks = event_system
event_system.connected_joysticks = (0..event_system
.joystick_subsystem
.joysticks()
.map_err(|s| anyhow::Error::msg(s))?
.num_joysticks()
.map_err(|s| anyhow::Error::msg(s))?)
.into_iter()
.map(|instance| {
Ok((
instance.id,
Joystick::new(&event_system.joystick_subsystem, instance)?,
))
})
.map(|i| Ok((i, Joystick::new(&event_system.joystick_subsystem, i)?)))
.collect::<Result<HashMap<_, _>>>()?;
event_system.connected_controllers = (0..event_system
.controller_subsystem
.num_gamepads()
.num_joysticks()
.map_err(|s| anyhow::Error::msg(s))?)
.into_iter()
.filter(|i| event_system.controller_subsystem.is_game_controller(*i))
@ -143,18 +143,56 @@ impl EventSystem {
.collect::<Result<HashMap<_, _>>>()?;
event_system.disable_mouse();
event_system.disable_keyboard();
event_system.disable_controller();
Ok(event_system)
}
pub fn enable_mouse(&mut self) {
self.event_pump.enable_event(SdlEventType::MouseMotion);
self.event_pump.enable_event(SdlEventType::MouseButtonDown);
self.event_pump.enable_event(SdlEventType::MouseButtonUp);
self.mouse.show_cursor(true);
}
pub fn disable_mouse(&mut self) {
self.event_pump.disable_event(SdlEventType::MouseMotion);
self.event_pump.disable_event(SdlEventType::MouseButtonDown);
self.event_pump.disable_event(SdlEventType::MouseButtonUp);
self.mouse.show_cursor(false);
}
pub fn enable_keyboard(&mut self) {
self.event_pump.enable_event(SdlEventType::KeyUp);
self.event_pump.enable_event(SdlEventType::KeyDown);
}
pub fn disable_keyboard(&mut self) {
self.event_pump.disable_event(SdlEventType::KeyUp);
self.event_pump.disable_event(SdlEventType::KeyDown);
}
pub fn enable_controller(&mut self) {
self.event_pump
.enable_event(SdlEventType::ControllerAxisMotion);
self.event_pump
.enable_event(SdlEventType::ControllerButtonDown);
self.event_pump
.enable_event(SdlEventType::ControllerButtonUp);
}
pub fn disable_controller(&mut self) {
self.event_pump
.disable_event(SdlEventType::ControllerAxisMotion);
self.event_pump
.disable_event(SdlEventType::ControllerButtonDown);
self.event_pump
.disable_event(SdlEventType::ControllerButtonUp);
}
pub fn set_controller_axis_enable_deadzone(&mut self, deadzone: f32) {
self.controller_deadzones.axis_enable_deadzone = deadzone;
}
@ -186,7 +224,7 @@ impl EventSystem {
for event in self.event_pump.poll_iter() {
match event {
SdlEvent::Window { win_event, .. } => match win_event {
WindowEvent::Resized(w, h) => {
WindowEvent::Resized(w, h) | WindowEvent::SizeChanged(w, h) => {
resize(w as u32, h as u32)?;
}
@ -224,7 +262,7 @@ impl EventSystem {
SdlEvent::MouseWheel {
x, y, direction, ..
} => {
event_callback(Event::MouseWheel(x as i32, y as i32, direction))?;
event_callback(Event::MouseWheel(x, y, direction))?;
}
// ------------------- Key Events ---------------------
SdlEvent::KeyDown {
@ -332,18 +370,10 @@ impl EventSystem {
event_callback(Event::ControllerAxis(&*controller))?;
}
SdlEvent::JoyDeviceAdded { which, .. } => {
if let Some(joystick_instance) = self
.joystick_subsystem
.joysticks()
.map_err(|_| anyhow!("failed querying joysticks"))?
.into_iter()
.find(|instance| instance.id == which)
{
let joystick = Joystick::new(&self.joystick_subsystem, joystick_instance)?;
let joystick = Joystick::new(&self.joystick_subsystem, which)?;
event_callback(Event::JoystickAdded(&joystick))?;
self.connected_joysticks.insert(joystick.id(), joystick);
}
event_callback(Event::JoystickAdded(&joystick))?;
self.connected_joysticks.insert(joystick.id(), joystick);
}
SdlEvent::JoyDeviceRemoved { which, .. } => {
if let Some(joysticks) = self.connected_joysticks.remove(&which) {

View file

@ -1,24 +1,25 @@
use anyhow::Result;
use sdl3::{JoystickSubsystem, joystick::JoystickInstance};
use sdl2::JoystickSubsystem;
pub struct Joystick {
sdl2_joystick: sdl3::joystick::Joystick,
_sdl2_joystick: sdl2::joystick::Joystick,
id: u32,
name: String,
}
impl Joystick {
pub fn new(joystick_subsystem: &JoystickSubsystem, instance: JoystickInstance) -> Result<Self> {
let sdl2_joystick = joystick_subsystem.open(instance)?;
pub fn new(joystick_subsystem: &JoystickSubsystem, id: u32) -> Result<Self> {
let sdl2_joystick = joystick_subsystem.open(id)?;
Ok(Self {
name: sdl2_joystick.name(),
sdl2_joystick,
id,
_sdl2_joystick: sdl2_joystick,
})
}
pub fn id(&self) -> u32 {
self.sdl2_joystick.instance_id()
self.id
}
pub fn name(&self) -> &str {
@ -29,7 +30,7 @@ impl Joystick {
impl std::fmt::Debug for Joystick {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Joystick")
.field("id", &self.id())
.field("id", &self.id)
.field("name", &self.name)
.finish()
}

View file

@ -16,7 +16,7 @@ pub use crate::input::{
// wsi
pub use crate::wsi::windowsystemintegration::{Display, WindowCreateInfo};
pub use sdl3::{keyboard::Keycode, mouse::MouseWheelDirection};
pub use sdl2::{keyboard::Keycode, mouse::MouseWheelDirection};
pub use vulkan_rs::prelude::*;

View file

@ -7,7 +7,7 @@ use crate::xri::openxrintegration::OpenXRIntegration;
use crate::Result;
use vulkan_rs::prelude::*;
use sdl3::Sdl;
use sdl2::Sdl;
use std::sync::{Arc, Mutex};
@ -88,8 +88,8 @@ impl PresentationCore {
window_create_info: &WindowCreateInfo,
appl_info: ApplicationInfo,
) -> Result<PresentationCore> {
// create sdl3 context
let context = sdl3::init().map_err(|s| anyhow::Error::msg(s))?;
// create sdl2 context
let context = sdl2::init().map_err(|s| anyhow::Error::msg(s))?;
Ok(PresentationCore {
event_system: EventSystem::new(&context)?,

View file

@ -1,20 +1,20 @@
// needed since RLS won't accept #[repr(C)]
#![allow(improper_ctypes)]
use anyhow::{Error, anyhow};
use sdl3::{
self, Sdl,
clipboard::ClipboardUtil,
messagebox::{MessageBoxFlag, show_simple_message_box},
mouse::Cursor,
surface::Surface as SDL_Surface,
video::{FullscreenType, WindowPos},
};
use anyhow::Error;
use sdl2;
use sdl2::Sdl;
use sdl2::clipboard::ClipboardUtil;
use sdl2::messagebox::{MessageBoxFlag, show_simple_message_box};
use sdl2::mouse::Cursor;
use sdl2::surface::Surface as SDL_Surface;
use sdl2::sys::SDL_Window;
use sdl2::video::{FullscreenType, WindowPos};
use crate::Result;
use vulkan_rs::prelude::*;
use std::mem::MaybeUninit;
use std::ops::Deref;
use std::path::Path;
use std::sync::{
@ -22,12 +22,30 @@ use std::sync::{
atomic::{AtomicI32, AtomicU32, Ordering::SeqCst},
};
const SDL_SYSWM_WINDOWS: u32 = 0x1;
const SDL_SYSWM_X11: u32 = 0x2;
const SDL_SYSWM_COCOA: u32 = 0x4;
const SDL_SYSWM_WAYLAND: u32 = 0x6;
const SDL_SYSWM_ANDROID: u32 = 0x9;
#[repr(C)]
struct SdlSysWmInfo {
version: sdl2::version::Version,
subsystem: u32,
info: [u64; 32],
}
unsafe extern "C" {
fn SDL_GetWindowWMInfo(window: *const sdl2::sys::SDL_Window, info: *mut SdlSysWmInfo) -> bool;
}
#[derive(Default, Debug, Clone)]
pub struct WindowCreateInfo {
pub title: String,
pub width: u32,
pub height: u32,
pub fullscreen: bool,
pub requested_display: Option<String>,
}
#[derive(Debug)]
@ -39,6 +57,8 @@ pub struct Display {
pub y: i32,
pub w: u32,
pub h: u32,
pub dpi: [f32; 3],
}
#[derive(Default, Debug)]
@ -50,7 +70,7 @@ struct CellRect {
}
impl CellRect {
fn update_from_window(&self, window: &sdl3::video::Window) {
fn update_from_window(&self, window: &sdl2::video::Window) {
let (w, h) = window.size();
let (x, y) = window.position();
@ -60,7 +80,7 @@ impl CellRect {
self.height.store(h, SeqCst);
}
fn update_to_window(&self, window: &mut sdl3::video::Window) -> Result<()> {
fn update_to_window(&self, window: &mut sdl2::video::Window) -> Result<()> {
set_window_size(window, self.width.load(SeqCst), self.height.load(SeqCst))?;
window.set_position(
WindowPos::Positioned(self.x.load(SeqCst)),
@ -73,12 +93,15 @@ impl CellRect {
pub struct WindowSystemIntegration {
// sdl
_video_subsystem: Mutex<sdl3::VideoSubsystem>,
window: Mutex<sdl3::video::Window>,
_video_subsystem: Mutex<sdl2::VideoSubsystem>,
window: Mutex<sdl2::video::Window>,
clipboard_util: ClipboardUtil,
cursor: Mutex<Option<Cursor>>,
displays: Vec<Display>,
_enabled_display_index: usize,
pre_fullscreen_rect: CellRect,
surface: Mutex<Option<Arc<Surface>>>,
@ -96,8 +119,8 @@ impl WindowSystemIntegration {
let video_subsystem = context.video().map_err(|s| anyhow::Error::msg(s))?;
// query display count
let display_count = match video_subsystem.displays() {
Ok(displays) => displays.len(),
let display_count = match video_subsystem.num_video_displays() {
Ok(num_displays) => num_displays,
Err(_) => 0,
};
@ -105,35 +128,78 @@ impl WindowSystemIntegration {
return Err(anyhow::Error::msg("No display where detected!"));
}
// // query display information
// let mut displays = Vec::with_capacity(display_count as usize);
// query display information
let mut displays = Vec::with_capacity(display_count as usize);
// for display in video_subsystem
// .displays()
// .map_err(|_| anyhow!("failed querying displays"))?
// {
// let rect = display.get_bounds().map_err(|s| anyhow::Error::msg(s))?;
// let name = display.get_name().map_err(|s| anyhow::Error::msg(s))?;
for i in 0..display_count {
let rect = video_subsystem
.display_bounds(i)
.map_err(|s| anyhow::Error::msg(s))?;
let name = video_subsystem
.display_name(i)
.map_err(|s| anyhow::Error::msg(s))?;
// let display = Display {
// name,
let (dpi0, dpi1, dpi2) = match video_subsystem.display_dpi(i) {
Ok(dpis) => dpis,
Err(msg) => {
println!("failed getting dpi for display {} ({}): {}", i, name, msg);
(0.0, 0.0, 0.0)
}
};
// x: rect.x(),
// y: rect.y(),
// w: rect.width(),
// h: rect.height(),
// };
let display = Display {
name,
// displays.push(display);
// }
x: rect.x(),
y: rect.y(),
w: rect.width(),
h: rect.height(),
dpi: [dpi0, dpi1, dpi2],
};
displays.push(display);
}
// check if there is an preferred display
let mut display_index = None;
if let Some(requested_display) = &create_info.requested_display {
match displays
.iter()
.position(|display| display.name == *requested_display)
{
Some(index) => display_index = Some(index),
None => {
println!("could not find display: {}", requested_display);
println!("defaulting to display 0 ({})", displays[0].name);
}
}
}
// build window
let mut window_builder =
video_subsystem.window(&create_info.title, create_info.width, create_info.height);
window_builder.resizable().vulkan();
window_builder.position_centered();
match display_index {
Some(index) => {
let display = &displays[index];
window_builder.position(
display.x + display.w as i32 / 2,
display.y + display.h as i32 / 2,
);
}
None => {
window_builder.position_centered();
}
}
let window = window_builder.build()?;
display_index = Some(window.display_index().map_err(|s| anyhow::Error::msg(s))? as usize);
let rect = CellRect::default();
rect.update_from_window(&window);
@ -144,6 +210,10 @@ impl WindowSystemIntegration {
cursor: Mutex::new(None),
displays,
_enabled_display_index: display_index.expect("display index not set"),
pre_fullscreen_rect: rect,
surface: Mutex::new(None),
@ -176,21 +246,20 @@ impl WindowSystemIntegration {
self.pre_fullscreen_rect.update_from_window(&window);
// set fullscreen size to fit display
let display = window.get_display().map_err(|s| anyhow!(s))?;
let rect = display.get_bounds().map_err(|s| anyhow!(s))?;
set_window_size(&mut window, rect.w as u32, rect.h as u32)?;
let display =
&self.displays[window.display_index().map_err(|s| anyhow::Error::msg(s))? as usize];
set_window_size(&mut window, display.w, display.h)?;
window.set_bordered(false);
// change fullscreen mode
window
.set_fullscreen(true)
.set_fullscreen(FullscreenType::True)
.map_err(|s| anyhow::Error::msg(s))?;
} else {
// change fullscreen mode
window
.set_fullscreen(false)
.set_fullscreen(FullscreenType::Off)
.map_err(|s| anyhow::Error::msg(s))?;
// force window borders
@ -302,16 +371,22 @@ impl WindowSystemIntegration {
Ok(())
}
fn raw_sdl2_window(&self) -> *mut SDL_Window {
self.window.lock().unwrap().raw()
}
pub fn displays(&self) -> &[Display] {
&self.displays
}
pub fn create_vulkan_surface(&self, instance: &Arc<Instance>) -> Result<()> {
let vk_surface = unsafe {
core::mem::transmute(
self.window
.lock()
.unwrap()
.vulkan_create_surface(core::mem::transmute(instance.vk_handle().raw()))
.map_err(|s| anyhow::Error::msg(s))?,
)
};
let vk_surface = self
.window
.lock()
.unwrap()
.vulkan_create_surface(instance.vk_handle().raw())
.map_err(|s| anyhow::Error::msg(s))?
.into();
*self.surface.lock().unwrap() = Some(Surface::from_vk_surface(vk_surface, instance));
@ -326,16 +401,28 @@ impl WindowSystemIntegration {
&self,
extensions: &mut InstanceExtensions,
) -> Result<()> {
let driver = self._video_subsystem.lock().unwrap().current_video_driver();
let sys_wm_info: SdlSysWmInfo = unsafe {
let tmp = MaybeUninit::zeroed();
let mut ret: SdlSysWmInfo = tmp.assume_init();
ret.version = sdl2::version::version();
match driver {
"android" => extensions.android_surface = true,
"cocoa" => extensions.macos_surface = true,
"x11" => extensions.xlib_surface = true,
"wayland" => extensions.wayland_surface = true,
"windows" => extensions.win32_surface = true,
SDL_GetWindowWMInfo(self.raw_sdl2_window(), &mut ret);
_ => panic!("unsupported video driver: {driver}"),
ret
};
match sys_wm_info.subsystem {
SDL_SYSWM_ANDROID => extensions.android_surface = true,
SDL_SYSWM_COCOA => extensions.macos_surface = true,
SDL_SYSWM_WAYLAND => extensions.wayland_surface = true,
SDL_SYSWM_WINDOWS => extensions.win32_surface = true,
SDL_SYSWM_X11 => extensions.xlib_surface = true,
_ => {
return Err(anyhow::Error::msg(format!(
"Unsupported window subsystem flag {}",
sys_wm_info.subsystem
)));
}
}
extensions.surface = true;
@ -361,7 +448,7 @@ impl std::fmt::Debug for WindowSystemIntegration {
/// helper function to wrap SDL2 error types
#[inline]
fn set_window_size(window: &mut sdl3::video::Window, width: u32, height: u32) -> Result<()> {
fn set_window_size(window: &mut sdl2::video::Window, width: u32, height: u32) -> Result<()> {
window.set_size(width, height)?;
Ok(())