use std::{
ffi::{c_void, CStr, CString},
os::raw::c_char,
};
use {bitflags::bitflags, rokol_ffi::app as ffi};
pub trait RApp {
fn init(&mut self) {}
fn frame(&mut self) {}
#[cfg(feature = "impl-gfx")]
fn cleanup(&mut self) {
unsafe {
rokol_ffi::gfx::sg_shutdown();
}
}
#[cfg(not(feature = "impl-gfx"))]
fn cleanup(&mut self);
fn event(&mut self, _ev: &Event) {}
fn fail(&mut self, msg: &str) {
eprint!("{}", msg);
}
}
pub trait RAppFfiCallback {
extern "C" fn init_userdata_cb(user_data: *mut c_void);
extern "C" fn frame_userdata_cb(user_data: *mut c_void);
extern "C" fn cleanup_userdata_cb(user_data: *mut c_void);
extern "C" fn event_userdata_cb(event: *const ffi::sapp_event, user_data: *mut c_void);
extern "C" fn fail_userdata_cb(message: *const c_char, user_data: *mut c_void);
}
impl<T: RApp> RAppFfiCallback for T {
extern "C" fn init_userdata_cb(user_data: *mut c_void) {
let me: &mut Self = unsafe { &mut *(user_data as *mut Self) };
me.init();
}
extern "C" fn frame_userdata_cb(user_data: *mut c_void) {
let me: &mut Self = unsafe { &mut *(user_data as *mut Self) };
me.frame();
}
extern "C" fn cleanup_userdata_cb(user_data: *mut c_void) {
let me: &mut Self = unsafe { &mut *(user_data as *mut Self) };
me.cleanup();
}
extern "C" fn event_userdata_cb(event: *const ffi::sapp_event, user_data: *mut c_void) {
let me: &mut Self = unsafe { &mut *(user_data as *mut Self) };
let ev: &Event = unsafe { &*(event as *const _) };
me.event(ev);
}
extern "C" fn fail_userdata_cb(message: *const c_char, user_data: *mut c_void) {
let msg = unsafe { CStr::from_ptr(message) };
let msg = match msg.to_str() {
Ok(msg) => msg,
Err(err) => {
eprintln!("Failed to read sokol_app message: {}", err);
return;
}
};
let me: &mut Self = unsafe { &mut *(user_data as *mut Self) };
me.fail(msg);
}
}
ffi_enum! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum EventType around ffi::sapp_event_type {
InvalidEvent = SAPP_EVENTTYPE_INVALID,
KeyDown = SAPP_EVENTTYPE_KEY_DOWN,
KeyUp = SAPP_EVENTTYPE_KEY_UP,
Char = SAPP_EVENTTYPE_CHAR,
MouseDown = SAPP_EVENTTYPE_MOUSE_DOWN,
MouseUp = SAPP_EVENTTYPE_MOUSE_UP,
MouseScroll = SAPP_EVENTTYPE_MOUSE_SCROLL,
MouseMove = SAPP_EVENTTYPE_MOUSE_MOVE,
MouseEnter = SAPP_EVENTTYPE_MOUSE_ENTER,
MouseLeave = SAPP_EVENTTYPE_MOUSE_LEAVE,
TouchesBegin = SAPP_EVENTTYPE_TOUCHES_BEGAN,
TouchesMoved = SAPP_EVENTTYPE_TOUCHES_MOVED,
TouchesEnded = SAPP_EVENTTYPE_TOUCHES_ENDED,
TouchesCancelled = SAPP_EVENTTYPE_TOUCHES_CANCELLED,
Resized = SAPP_EVENTTYPE_RESIZED,
Iconified = SAPP_EVENTTYPE_ICONIFIED,
Restored = SAPP_EVENTTYPE_RESTORED,
Focused = SAPP_EVENTTYPE_FOCUSED,
Unocused = SAPP_EVENTTYPE_UNFOCUSED,
Suspended = SAPP_EVENTTYPE_SUSPENDED,
Resumed = SAPP_EVENTTYPE_RESUMED,
UpdateCursor = SAPP_EVENTTYPE_UPDATE_CURSOR,
QuitRequested = SAPP_EVENTTYPE_QUIT_REQUESTED,
ClipboardPasted = SAPP_EVENTTYPE_CLIPBOARD_PASTED,
FilesDropped = SAPP_EVENTTYPE_FILES_DROPPED,
_Num = _SAPP_EVENTTYPE_NUM,
_ForceU32 = _SAPP_EVENTTYPE_FORCE_U32,
}
}
ffi_enum! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Key around ffi::sapp_keycode {
InvalidKey = SAPP_KEYCODE_INVALID,
Space = SAPP_KEYCODE_SPACE,
Apostrophe = SAPP_KEYCODE_APOSTROPHE,
Comma = SAPP_KEYCODE_COMMA,
Minus = SAPP_KEYCODE_MINUS,
Period = SAPP_KEYCODE_PERIOD,
Slash = SAPP_KEYCODE_SLASH,
Kbd0 = SAPP_KEYCODE_0,
Kbd1 = SAPP_KEYCODE_1,
Kbd2 = SAPP_KEYCODE_2,
Kbd3 = SAPP_KEYCODE_3,
Kbd4 = SAPP_KEYCODE_4,
Kbd5 = SAPP_KEYCODE_5,
Kbd6 = SAPP_KEYCODE_6,
Kbd7 = SAPP_KEYCODE_7,
Kbd8 = SAPP_KEYCODE_8,
Kbd9 = SAPP_KEYCODE_9,
Semicolon = SAPP_KEYCODE_SEMICOLON,
Equal = SAPP_KEYCODE_EQUAL,
A = SAPP_KEYCODE_A,
B = SAPP_KEYCODE_B,
C = SAPP_KEYCODE_C,
D = SAPP_KEYCODE_D,
E = SAPP_KEYCODE_E,
F = SAPP_KEYCODE_F,
G = SAPP_KEYCODE_G,
H = SAPP_KEYCODE_H,
I = SAPP_KEYCODE_I,
J = SAPP_KEYCODE_J,
K = SAPP_KEYCODE_K,
L = SAPP_KEYCODE_L,
M = SAPP_KEYCODE_M,
N = SAPP_KEYCODE_N,
O = SAPP_KEYCODE_O,
P = SAPP_KEYCODE_P,
Q = SAPP_KEYCODE_Q,
R = SAPP_KEYCODE_R,
S = SAPP_KEYCODE_S,
T = SAPP_KEYCODE_T,
U = SAPP_KEYCODE_U,
V = SAPP_KEYCODE_V,
W = SAPP_KEYCODE_W,
X = SAPP_KEYCODE_X,
Y = SAPP_KEYCODE_Y,
Z = SAPP_KEYCODE_Z,
LeftBracket = SAPP_KEYCODE_LEFT_BRACKET,
Backslash = SAPP_KEYCODE_BACKSLASH,
RightBracket = SAPP_KEYCODE_RIGHT_BRACKET,
GraveAccent = SAPP_KEYCODE_GRAVE_ACCENT,
World1 = SAPP_KEYCODE_WORLD_1,
World2 = SAPP_KEYCODE_WORLD_2,
Escape = SAPP_KEYCODE_ESCAPE,
Enter = SAPP_KEYCODE_ENTER,
Tab = SAPP_KEYCODE_TAB,
Backspace = SAPP_KEYCODE_BACKSPACE,
Insert = SAPP_KEYCODE_INSERT,
Delete = SAPP_KEYCODE_DELETE,
Right = SAPP_KEYCODE_RIGHT,
Left = SAPP_KEYCODE_LEFT,
Down = SAPP_KEYCODE_DOWN,
Up = SAPP_KEYCODE_UP,
PageUp = SAPP_KEYCODE_PAGE_UP,
PageDown = SAPP_KEYCODE_PAGE_DOWN,
Home = SAPP_KEYCODE_HOME,
End = SAPP_KEYCODE_END,
CapsLock = SAPP_KEYCODE_CAPS_LOCK,
ScrollLock = SAPP_KEYCODE_SCROLL_LOCK,
NumLock = SAPP_KEYCODE_NUM_LOCK,
PrintScreen = SAPP_KEYCODE_PRINT_SCREEN,
Pause = SAPP_KEYCODE_PAUSE,
F1 = SAPP_KEYCODE_F1,
F2 = SAPP_KEYCODE_F2,
F3 = SAPP_KEYCODE_F3,
F4 = SAPP_KEYCODE_F4,
F5 = SAPP_KEYCODE_F5,
F6 = SAPP_KEYCODE_F6,
F7 = SAPP_KEYCODE_F7,
F8 = SAPP_KEYCODE_F8,
F9 = SAPP_KEYCODE_F9,
F10 = SAPP_KEYCODE_F10,
F11 = SAPP_KEYCODE_F11,
F12 = SAPP_KEYCODE_F12,
F13 = SAPP_KEYCODE_F13,
F14 = SAPP_KEYCODE_F14,
F15 = SAPP_KEYCODE_F15,
F16 = SAPP_KEYCODE_F16,
F17 = SAPP_KEYCODE_F17,
F18 = SAPP_KEYCODE_F18,
F19 = SAPP_KEYCODE_F19,
F20 = SAPP_KEYCODE_F20,
F21 = SAPP_KEYCODE_F21,
F22 = SAPP_KEYCODE_F22,
F23 = SAPP_KEYCODE_F23,
F24 = SAPP_KEYCODE_F24,
F25 = SAPP_KEYCODE_F25,
KP0 = SAPP_KEYCODE_KP_0,
KP1 = SAPP_KEYCODE_KP_1,
KP2 = SAPP_KEYCODE_KP_2,
KP3 = SAPP_KEYCODE_KP_3,
KP4 = SAPP_KEYCODE_KP_4,
KP5 = SAPP_KEYCODE_KP_5,
KP6 = SAPP_KEYCODE_KP_6,
KP7 = SAPP_KEYCODE_KP_7,
KP8 = SAPP_KEYCODE_KP_8,
KP9 = SAPP_KEYCODE_KP_9,
KPDecimal = SAPP_KEYCODE_KP_DECIMAL,
KPDivide = SAPP_KEYCODE_KP_DIVIDE,
KPMultiply = SAPP_KEYCODE_KP_MULTIPLY,
KPSubtract = SAPP_KEYCODE_KP_SUBTRACT,
KPAdd = SAPP_KEYCODE_KP_ADD,
KPEnter = SAPP_KEYCODE_KP_ENTER,
KPEqual = SAPP_KEYCODE_KP_EQUAL,
LeftShift = SAPP_KEYCODE_LEFT_SHIFT,
LeftControl = SAPP_KEYCODE_LEFT_CONTROL,
LeftAlt = SAPP_KEYCODE_LEFT_ALT,
LeftSuper = SAPP_KEYCODE_LEFT_SUPER,
RightShift = SAPP_KEYCODE_RIGHT_SHIFT,
RightControl = SAPP_KEYCODE_RIGHT_CONTROL,
RightAlt = SAPP_KEYCODE_RIGHT_ALT,
RightSuper = SAPP_KEYCODE_RIGHT_SUPER,
Menu = SAPP_KEYCODE_MENU,
}
}
ffi_enum! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Mouse around ffi::sapp_mousebutton {
Invalid = SAPP_MOUSEBUTTON_INVALID,
Left = SAPP_MOUSEBUTTON_LEFT,
Right = SAPP_MOUSEBUTTON_RIGHT,
Middle = SAPP_MOUSEBUTTON_MIDDLE,
}
}
bitflags! {
pub struct Mod: u32 {
const SHIFT = ffi::SAPP_MODIFIER_SHIFT as u32;
const CONTROL = ffi::SAPP_MODIFIER_CTRL as u32;
const ALT = ffi::SAPP_MODIFIER_ALT as u32;
const SUPER = ffi::SAPP_MODIFIER_SUPER as u32;
}
}
pub type TouchPoint = ffi::sapp_touchpoint;
pub type Event = ffi::sapp_event;
pub type Range = ffi::sapp_range;
pub type IconDesc = ffi::sapp_icon_desc;
pub fn set_icon(icon: &IconDesc) {
unsafe {
ffi::sapp_set_icon(icon as *const _);
}
}
pub fn is_valid() -> bool {
unsafe { ffi::sapp_isvalid() }
}
pub fn width() -> u32 {
unsafe { ffi::sapp_width() as u32 }
}
pub fn height() -> u32 {
unsafe { ffi::sapp_height() as u32 }
}
pub fn size() -> [u32; 2] {
[self::width(), self::height()]
}
pub fn width_f() -> f32 {
unsafe { ffi::sapp_widthf() }
}
pub fn height_f() -> f32 {
unsafe { ffi::sapp_heightf() }
}
pub fn size_f() -> [f32; 2] {
[self::width_f(), self::height_f()]
}
pub fn size_f_scaled() -> [f32; 2] {
[
self::width_f() / self::dpi_scale(),
self::height_f() / self::dpi_scale(),
]
}
pub fn color_fmt() -> i32 {
unsafe { ffi::sapp_color_format() }
}
pub fn depth_format() -> i32 {
unsafe { ffi::sapp_depth_format() }
}
pub fn sample_count() -> u32 {
unsafe { ffi::sapp_sample_count() as u32 }
}
pub fn is_high_dpi() -> bool {
unsafe { ffi::sapp_high_dpi() }
}
pub fn dpi_scale() -> f32 {
unsafe { ffi::sapp_dpi_scale() }
}
pub fn set_show_kbd(do_show: bool) {
unsafe {
ffi::sapp_show_keyboard(do_show);
}
}
pub fn is_kbd_shown() -> bool {
unsafe { ffi::sapp_keyboard_shown() }
}
pub fn is_fullscreen() -> bool {
unsafe { ffi::sapp_is_fullscreen() }
}
pub fn toggle_fullscreen() {
unsafe { ffi::sapp_toggle_fullscreen() }
}
pub fn set_show_mouse(show: bool) {
unsafe {
ffi::sapp_show_mouse(show);
}
}
pub fn is_mouse_shown() -> bool {
unsafe { ffi::sapp_mouse_shown() }
}
pub fn set_lock_mouse(lock: bool) {
unsafe {
ffi::sapp_lock_mouse(lock);
}
}
pub fn is_mouse_locked() -> bool {
unsafe { ffi::sapp_mouse_locked() }
}
pub fn request_quit() {
unsafe { ffi::sapp_request_quit() }
}
pub fn cancel_quit() {
unsafe { ffi::sapp_cancel_quit() }
}
pub fn quit() {
unsafe {
ffi::sapp_quit();
}
}
pub fn consume_event() {
unsafe {
ffi::sapp_consume_event();
}
}
pub fn frame_count() -> u64 {
unsafe { ffi::sapp_frame_count() }
}
pub fn frame_duration() -> f64 {
unsafe { ffi::sapp_frame_duration() }
}
pub fn set_clipboard(s: &str) -> Result<(), std::ffi::NulError> {
let c_str = CString::new(s)?;
unsafe {
ffi::sapp_set_clipboard_string(c_str.as_ptr() as *mut _);
}
Ok(())
}
pub fn clipboard() -> Result<String, std::str::Utf8Error> {
let ptr = unsafe { ffi::sapp_get_clipboard_string() };
let c_str = unsafe { CStr::from_ptr(ptr) };
c_str.to_str().map(|s| s.to_string())
}
pub fn set_win_title(title: &str) -> Result<(), std::ffi::NulError> {
let c_str = CString::new(title)?;
unsafe { ffi::sapp_set_window_title(c_str.as_ptr() as *mut _) };
Ok(())
}
pub fn n_dropped_files() -> u32 {
unsafe { ffi::sapp_get_num_dropped_files() as u32 }
}
pub fn dropped_file_path(ix: u32) -> Result<String, std::str::Utf8Error> {
let ptr = unsafe { ffi::sapp_get_dropped_file_path(ix as i32) };
let c_str = unsafe { CString::from_raw(ptr as *mut _) };
c_str.to_str().map(|s| s.to_string())
}