use crate::{drawing::DrawHandle, ffi, math::Vector2, texture::Image};
use std::{
ffi::{CStr, CString},
time::Duration, sync::atomic::{AtomicBool, Ordering}, marker::PhantomData,
};
pub use ffi::{
ConfigFlags, GamepadAxis, GamepadButton, Gesture, KeyboardKey, MouseButton, MouseCursor,
};
static INITIALIZED: AtomicBool = AtomicBool::new(false);
#[derive(Debug)]
pub struct Raylib(PhantomData<*const ()>);
impl Raylib {
#[inline]
pub fn init_window(width: u32, height: u32, title: &str) -> Option<Self> {
if !INITIALIZED.load(Ordering::Relaxed) {
let title = CString::new(title).unwrap();
unsafe {
ffi::InitWindow(width as _, height as _, title.as_ptr());
}
if unsafe { ffi::IsWindowReady() } {
INITIALIZED.store(true, Ordering::Relaxed);
Some(Self(PhantomData))
} else {
None
}
} else {
None
}
}
#[inline]
pub fn init_window_ex(
width: u32,
height: u32,
title: &str,
flags: ConfigFlags,
) -> Option<Self> {
unsafe {
ffi::SetConfigFlags(flags.bits());
}
Self::init_window(width, height, title)
}
#[inline]
pub fn window_should_close(&self) -> bool {
unsafe { ffi::WindowShouldClose() }
}
#[inline]
pub fn close_window(self) {
drop(self)
}
#[inline]
pub fn is_window_fullscreen(&self) -> bool {
unsafe { ffi::IsWindowFullscreen() }
}
#[inline]
pub fn is_window_hidden(&self) -> bool {
unsafe { ffi::IsWindowHidden() }
}
#[inline]
pub fn is_window_minimized(&self) -> bool {
unsafe { ffi::IsWindowMinimized() }
}
#[inline]
pub fn is_window_maximized(&self) -> bool {
unsafe { ffi::IsWindowMaximized() }
}
#[inline]
pub fn is_window_focused(&self) -> bool {
unsafe { ffi::IsWindowFocused() }
}
#[inline]
pub fn is_window_resized(&self) -> bool {
unsafe { ffi::IsWindowResized() }
}
#[inline]
pub fn is_window_state(&self, flag: ConfigFlags) -> bool {
unsafe { ffi::IsWindowState(flag.bits()) }
}
#[inline]
pub fn set_window_state(&mut self, flags: ConfigFlags) {
unsafe { ffi::SetWindowState(flags.bits()) }
}
#[inline]
pub fn clear_window_state(&mut self, flags: ConfigFlags) {
unsafe { ffi::ClearWindowState(flags.bits()) }
}
#[inline]
pub fn toggle_fullscreen(&mut self) {
unsafe { ffi::ToggleFullscreen() }
}
#[inline]
pub fn maximize_window(&mut self) {
unsafe { ffi::MaximizeWindow() }
}
#[inline]
pub fn minimize_window(&mut self) {
unsafe { ffi::MinimizeWindow() }
}
#[inline]
pub fn restore_window(&mut self) {
unsafe { ffi::RestoreWindow() }
}
#[inline]
pub fn set_window_icon(&mut self, image: &Image) {
unsafe { ffi::SetWindowIcon(image.raw.clone()) }
}
#[inline]
pub fn set_window_icons(&mut self, images: &[&Image]) {
let mut images: Vec<_> = images.iter().map(|img| img.raw.clone()).collect();
unsafe { ffi::SetWindowIcons(images.as_mut_ptr(), images.len() as _) }
}
#[inline]
pub fn set_window_title(&mut self, title: &str) {
let title = CString::new(title).unwrap();
unsafe { ffi::SetWindowTitle(title.as_ptr()) }
}
#[inline]
pub fn set_window_position(&mut self, x: i32, y: i32) {
unsafe { ffi::SetWindowPosition(x, y) }
}
#[inline]
pub fn set_window_monitor(&mut self, monitor: u32) {
unsafe { ffi::SetWindowMonitor(monitor as _) }
}
#[inline]
pub fn set_window_min_size(&mut self, width: u32, height: u32) {
unsafe { ffi::SetWindowMinSize(width as _, height as _) }
}
#[inline]
pub fn set_window_size(&mut self, width: u32, height: u32) {
unsafe { ffi::SetWindowSize(width as _, height as _) }
}
#[inline]
pub fn set_window_opacity(&mut self, opacity: f32) {
unsafe { ffi::SetWindowOpacity(opacity) }
}
#[inline]
pub fn get_window_handle(&self) -> *mut core::ffi::c_void {
unsafe { ffi::GetWindowHandle() }
}
#[inline]
pub fn get_screen_width(&self) -> u32 {
unsafe { ffi::GetScreenWidth() as _ }
}
#[inline]
pub fn get_screen_height(&self) -> u32 {
unsafe { ffi::GetScreenHeight() as _ }
}
#[inline]
pub fn get_render_width(&self) -> u32 {
unsafe { ffi::GetRenderWidth() as _ }
}
#[inline]
pub fn get_render_height(&self) -> u32 {
unsafe { ffi::GetRenderHeight() as _ }
}
#[inline]
pub fn get_monitor_count(&self) -> u32 {
unsafe { ffi::GetMonitorCount() as _ }
}
#[inline]
pub fn get_current_monitor(&self) -> u32 {
unsafe { ffi::GetCurrentMonitor() as _ }
}
#[inline]
pub fn get_monitor_position(&self, monitor: u32) -> Vector2 {
unsafe { ffi::GetMonitorPosition(monitor as _).into() }
}
#[inline]
pub fn get_monitor_width(&self, monitor: u32) -> u32 {
unsafe { ffi::GetMonitorWidth(monitor as _) as _ }
}
#[inline]
pub fn get_monitor_height(&self, monitor: u32) -> u32 {
unsafe { ffi::GetMonitorHeight(monitor as _) as _ }
}
#[inline]
pub fn get_monitor_physical_width(&self, monitor: u32) -> u32 {
unsafe { ffi::GetMonitorPhysicalWidth(monitor as _) as _ }
}
#[inline]
pub fn get_monitor_physical_height(&self, monitor: u32) -> u32 {
unsafe { ffi::GetMonitorPhysicalHeight(monitor as _) as _ }
}
#[inline]
pub fn get_monitor_refresh_rate(&self, monitor: u32) -> u32 {
unsafe { ffi::GetMonitorRefreshRate(monitor as _) as _ }
}
#[inline]
pub fn get_window_position(&self) -> Vector2 {
unsafe { ffi::GetWindowPosition().into() }
}
#[inline]
pub fn get_window_scale_dpi(&self) -> Vector2 {
unsafe { ffi::GetWindowScaleDPI().into() }
}
#[inline]
pub fn get_monitor_name(&self, monitor: u32) -> String {
let name = unsafe { ffi::GetMonitorName(monitor as _) };
if name.is_null() {
String::new()
} else {
unsafe { CStr::from_ptr(name) }
.to_string_lossy()
.into_owned()
}
}
#[inline]
pub fn set_clipboard_text(&mut self, text: &str) {
let text = CString::new(text).unwrap();
unsafe { ffi::SetClipboardText(text.as_ptr()) }
}
#[inline]
pub fn get_clipboard_text(&self) -> String {
let text = unsafe { ffi::GetClipboardText() };
if text.is_null() {
String::new()
} else {
unsafe { CStr::from_ptr(text) }
.to_string_lossy()
.into_owned()
}
}
#[inline]
pub fn enable_event_waiting(&mut self) {
unsafe { ffi::EnableEventWaiting() }
}
#[inline]
pub fn disable_event_waiting(&mut self) {
unsafe { ffi::DisableEventWaiting() }
}
#[inline]
pub fn swap_screen_buffer(&mut self) {
unsafe { ffi::SwapScreenBuffer() }
}
#[inline]
pub fn poll_input_events(&mut self) {
unsafe { ffi::PollInputEvents() }
}
#[inline]
pub fn wait_time(&mut self, duration: Duration) {
unsafe { ffi::WaitTime(duration.as_secs_f64()) }
}
#[inline]
pub fn show_cursor(&mut self) {
unsafe { ffi::ShowCursor() }
}
#[inline]
pub fn hide_cursor(&mut self) {
unsafe { ffi::HideCursor() }
}
#[inline]
pub fn is_cursor_hidden(&self) -> bool {
unsafe { ffi::IsCursorHidden() }
}
#[inline]
pub fn enable_cursor(&mut self) {
unsafe { ffi::EnableCursor() }
}
#[inline]
pub fn disable_cursor(&mut self) {
unsafe { ffi::DisableCursor() }
}
#[inline]
pub fn is_cursor_on_screen(&self) -> bool {
unsafe { ffi::IsCursorOnScreen() }
}
#[inline]
pub fn set_target_fps(&mut self, fps: u32) {
unsafe { ffi::SetTargetFPS(fps as _) }
}
#[inline]
pub fn get_fps(&self) -> u32 {
unsafe { ffi::GetFPS() as _ }
}
#[inline]
pub fn get_frame_time(&self) -> Duration {
Duration::from_secs_f32(unsafe { ffi::GetFrameTime() })
}
#[inline]
pub fn get_time(&self) -> Duration {
Duration::from_secs_f64(unsafe { ffi::GetTime() })
}
#[inline]
pub fn get_random_value(&self, min: i32, max: i32) -> i32 {
unsafe { ffi::GetRandomValue(min, max) }
}
#[inline]
pub fn set_random_seed(&mut self, seed: u32) {
unsafe { ffi::SetRandomSeed(seed) }
}
#[inline]
pub fn take_screenshot(&mut self, file_name: &str) {
let file_name = CString::new(file_name).unwrap();
unsafe { ffi::TakeScreenshot(file_name.as_ptr()) }
}
#[inline]
pub fn open_url(&self, url: &str) {
let url = CString::new(url).unwrap();
unsafe { ffi::OpenURL(url.as_ptr()) }
}
#[inline]
pub fn is_file_dropped(&self) -> bool {
unsafe { ffi::IsFileDropped() }
}
#[inline]
pub fn get_dropped_files(&self) -> Vec<String> {
let path_list = unsafe { ffi::LoadDroppedFiles() };
let mut paths = Vec::new();
for i in 0..(path_list.count as usize) {
let path = unsafe { CStr::from_ptr(path_list.paths.add(i).read()) };
paths.push(path.to_string_lossy().into_owned());
}
unsafe {
ffi::UnloadDroppedFiles(path_list);
}
paths
}
#[inline]
pub fn is_key_pressed(&self, key: KeyboardKey) -> bool {
unsafe { ffi::IsKeyPressed(key as _) }
}
#[inline]
pub fn is_key_down(&self, key: KeyboardKey) -> bool {
unsafe { ffi::IsKeyDown(key as _) }
}
#[inline]
pub fn is_key_released(&self, key: KeyboardKey) -> bool {
unsafe { ffi::IsKeyReleased(key as _) }
}
#[inline]
pub fn is_key_up(&self, key: KeyboardKey) -> bool {
unsafe { ffi::IsKeyUp(key as _) }
}
#[inline]
pub fn set_exit_key(&mut self, key: KeyboardKey) {
unsafe { ffi::SetExitKey(key as _) }
}
#[inline]
pub fn get_key_pressed(&self) -> KeyboardKey {
unsafe { std::mem::transmute(ffi::GetKeyPressed()) }
}
#[inline]
pub fn get_char_pressed(&self) -> Option<char> {
let ch = unsafe { ffi::GetCharPressed() as u32 };
if ch != 0 {
char::from_u32(ch)
} else {
None
}
}
#[inline]
pub fn is_gamepad_available(&self, gamepad: u32) -> bool {
unsafe { ffi::IsGamepadAvailable(gamepad as _) }
}
#[inline]
pub fn get_gamepad_name(&self, gamepad: u32) -> String {
let name = unsafe { ffi::GetGamepadName(gamepad as _) };
if !name.is_null() {
let name = unsafe { CStr::from_ptr(name) };
name.to_string_lossy().into_owned()
} else {
String::new()
}
}
#[inline]
pub fn is_gamepad_button_pressed(&self, gamepad: u32, button: GamepadButton) -> bool {
unsafe { ffi::IsGamepadButtonPressed(gamepad as _, button as _) }
}
#[inline]
pub fn is_gamepad_button_down(&self, gamepad: u32, button: GamepadButton) -> bool {
unsafe { ffi::IsGamepadButtonDown(gamepad as _, button as _) }
}
#[inline]
pub fn is_gamepad_button_released(&self, gamepad: u32, button: GamepadButton) -> bool {
unsafe { ffi::IsGamepadButtonReleased(gamepad as _, button as _) }
}
#[inline]
pub fn is_gamepad_button_up(&self, gamepad: u32, button: GamepadButton) -> bool {
unsafe { ffi::IsGamepadButtonUp(gamepad as _, button as _) }
}
#[inline]
pub fn get_gamepad_button_pressed(&self) -> GamepadButton {
unsafe { std::mem::transmute(ffi::GetGamepadButtonPressed()) }
}
#[inline]
pub fn get_gamepad_axis_count(&self, gamepad: u32) -> u32 {
unsafe { ffi::GetGamepadAxisCount(gamepad as _) as _ }
}
#[inline]
pub fn get_gamepad_axis_movement(&self, gamepad: u32, axis: GamepadAxis) -> f32 {
unsafe { ffi::GetGamepadAxisMovement(gamepad as _, axis as _) }
}
#[inline]
pub fn set_gamepad_mappings(&mut self, mappings: &str) -> i32 {
let mappings = CString::new(mappings).unwrap();
unsafe { ffi::SetGamepadMappings(mappings.as_ptr()) }
}
#[inline]
pub fn is_mouse_button_pressed(&self, button: MouseButton) -> bool {
unsafe { ffi::IsMouseButtonPressed(button as _) }
}
#[inline]
pub fn is_mouse_button_down(&self, button: MouseButton) -> bool {
unsafe { ffi::IsMouseButtonDown(button as _) }
}
#[inline]
pub fn is_mouse_button_released(&self, button: MouseButton) -> bool {
unsafe { ffi::IsMouseButtonReleased(button as _) }
}
#[inline]
pub fn is_mouse_button_up(&self, button: MouseButton) -> bool {
unsafe { ffi::IsMouseButtonUp(button as _) }
}
#[inline]
pub fn get_mouse_x(&self) -> i32 {
unsafe { ffi::GetMouseX() }
}
#[inline]
pub fn get_mouse_y(&self) -> i32 {
unsafe { ffi::GetMouseY() }
}
#[inline]
pub fn get_mouse_position(&self) -> Vector2 {
unsafe { ffi::GetMousePosition().into() }
}
#[inline]
pub fn get_mouse_delta(&self) -> Vector2 {
unsafe { ffi::GetMouseDelta().into() }
}
#[inline]
pub fn set_mouse_position(&mut self, x: i32, y: i32) {
unsafe { ffi::SetMousePosition(x, y) }
}
#[inline]
pub fn set_mouse_offset(&mut self, offset_x: i32, offset_y: i32) {
unsafe { ffi::SetMouseOffset(offset_x, offset_y) }
}
#[inline]
pub fn set_mouse_scale(&mut self, scale_x: f32, scale_y: f32) {
unsafe { ffi::SetMouseScale(scale_x, scale_y) }
}
#[inline]
pub fn get_mouse_wheel_move(&self) -> f32 {
unsafe { ffi::GetMouseWheelMove() }
}
#[inline]
pub fn get_mouse_wheel_move_vec(&self) -> Vector2 {
unsafe { ffi::GetMouseWheelMoveV().into() }
}
#[inline]
pub fn set_mouse_cursor(&mut self, cursor: MouseCursor) {
unsafe { ffi::SetMouseCursor(cursor as _) }
}
#[inline]
pub fn get_touch_x(&self) -> i32 {
unsafe { ffi::GetTouchX() }
}
#[inline]
pub fn get_touch_y(&self) -> i32 {
unsafe { ffi::GetTouchY() }
}
#[inline]
pub fn get_touch_position(&self, index: u32) -> Vector2 {
unsafe { ffi::GetTouchPosition(index as _).into() }
}
#[inline]
pub fn get_touch_point_id(&self, index: u32) -> u32 {
unsafe { ffi::GetTouchPointId(index as _) as _ }
}
#[inline]
pub fn get_touch_point_count(&self) -> u32 {
unsafe { ffi::GetTouchPointCount() as _ }
}
#[inline]
pub fn set_gestures_enabled(&mut self, flags: Gesture) {
unsafe { ffi::SetGesturesEnabled(flags.bits()) }
}
#[inline]
pub fn is_gesture_detected(&self, gesture: Gesture) -> bool {
unsafe { ffi::IsGestureDetected(gesture.bits() as _) }
}
#[inline]
pub fn get_gesture_detected(&self) -> Gesture {
unsafe { Gesture(ffi::GetGestureDetected() as _) }
}
#[inline]
pub fn get_gesture_hold_duration(&self) -> Duration {
Duration::from_micros(unsafe { ffi::GetGestureHoldDuration() * 1000. } as u64)
}
#[inline]
pub fn get_gesture_drag_vector(&self) -> Vector2 {
unsafe { ffi::GetGestureDragVector().into() }
}
#[inline]
pub fn get_gesture_drag_angle(&self) -> f32 {
unsafe { ffi::GetGestureDragAngle() }
}
#[inline]
pub fn get_gesture_pinch_vector(&self) -> Vector2 {
unsafe { ffi::GetGesturePinchVector().into() }
}
#[inline]
pub fn get_gesture_pinch_angle(&self) -> f32 {
unsafe { ffi::GetGesturePinchAngle() }
}
#[inline]
pub fn begin_drawing(&mut self) -> DrawHandle {
unsafe {
ffi::BeginDrawing();
}
DrawHandle(self)
}
}
impl Drop for Raylib {
#[inline]
fn drop(&mut self) {
unsafe { ffi::CloseWindow() }
}
}