1use crate::{drawing::DrawHandle, ffi, math::Vector2, texture::Image};
2
3use std::{
4 ffi::{CStr, CString},
5 marker::PhantomData,
6 sync::atomic::{AtomicBool, Ordering},
7 time::Duration,
8};
9
10pub use ffi::{
11 ConfigFlags, GamepadAxis, GamepadButton, Gesture, KeyboardKey, MouseButton, MouseCursor,
12 TraceLogLevel,
13};
14
15static INITIALIZED: AtomicBool = AtomicBool::new(false);
16
17#[derive(Debug)]
19pub struct Raylib(PhantomData<*const ()>);
20
21impl Raylib {
22 #[inline]
24 pub fn init_window(width: u32, height: u32, title: &str) -> Option<Self> {
25 if !INITIALIZED.load(Ordering::Relaxed) {
26 let title = CString::new(title).unwrap();
27
28 unsafe {
29 ffi::InitWindow(width as _, height as _, title.as_ptr());
30 }
31
32 if unsafe { ffi::IsWindowReady() } {
33 INITIALIZED.store(true, Ordering::Relaxed);
34
35 Some(Self(PhantomData))
36 } else {
37 None
38 }
39 } else {
40 None
41 }
42 }
43
44 #[inline]
46 pub fn init_window_ex(
47 width: u32,
48 height: u32,
49 title: &str,
50 flags: ConfigFlags,
51 ) -> Option<Self> {
52 unsafe {
53 ffi::SetConfigFlags(flags.bits());
54 }
55
56 Self::init_window(width, height, title)
57 }
58
59 #[inline]
61 pub fn window_should_close(&self) -> bool {
62 unsafe { ffi::WindowShouldClose() }
63 }
64
65 #[inline]
67 pub fn close_window(self) {
68 drop(self)
69 }
70
71 #[inline]
73 pub fn is_window_fullscreen(&self) -> bool {
74 unsafe { ffi::IsWindowFullscreen() }
75 }
76
77 #[inline]
79 pub fn is_window_hidden(&self) -> bool {
80 unsafe { ffi::IsWindowHidden() }
81 }
82
83 #[inline]
85 pub fn is_window_minimized(&self) -> bool {
86 unsafe { ffi::IsWindowMinimized() }
87 }
88
89 #[inline]
91 pub fn is_window_maximized(&self) -> bool {
92 unsafe { ffi::IsWindowMaximized() }
93 }
94
95 #[inline]
97 pub fn is_window_focused(&self) -> bool {
98 unsafe { ffi::IsWindowFocused() }
99 }
100
101 #[inline]
103 pub fn is_window_resized(&self) -> bool {
104 unsafe { ffi::IsWindowResized() }
105 }
106
107 #[inline]
109 pub fn is_window_state(&self, flag: ConfigFlags) -> bool {
110 unsafe { ffi::IsWindowState(flag.bits()) }
111 }
112
113 #[inline]
115 pub fn set_window_state(&mut self, flags: ConfigFlags) {
116 unsafe { ffi::SetWindowState(flags.bits()) }
117 }
118
119 #[inline]
121 pub fn clear_window_state(&mut self, flags: ConfigFlags) {
122 unsafe { ffi::ClearWindowState(flags.bits()) }
123 }
124
125 #[inline]
127 pub fn toggle_fullscreen(&mut self) {
128 unsafe { ffi::ToggleFullscreen() }
129 }
130
131 #[inline]
133 pub fn maximize_window(&mut self) {
134 unsafe { ffi::MaximizeWindow() }
135 }
136
137 #[inline]
139 pub fn minimize_window(&mut self) {
140 unsafe { ffi::MinimizeWindow() }
141 }
142
143 #[inline]
145 pub fn restore_window(&mut self) {
146 unsafe { ffi::RestoreWindow() }
147 }
148
149 #[inline]
151 pub fn set_window_icon(&mut self, image: &Image) {
152 unsafe { ffi::SetWindowIcon(image.raw.clone()) }
153 }
154
155 #[inline]
157 pub fn set_window_icons(&mut self, images: &[&Image]) {
158 let mut images: Vec<_> = images.iter().map(|img| img.raw.clone()).collect();
159
160 unsafe { ffi::SetWindowIcons(images.as_mut_ptr(), images.len() as _) }
161 }
162
163 #[inline]
165 pub fn set_window_title(&mut self, title: &str) {
166 let title = CString::new(title).unwrap();
167
168 unsafe { ffi::SetWindowTitle(title.as_ptr()) }
169 }
170
171 #[inline]
173 pub fn set_window_position(&mut self, x: i32, y: i32) {
174 unsafe { ffi::SetWindowPosition(x, y) }
175 }
176
177 #[inline]
179 pub fn set_window_monitor(&mut self, monitor: u32) {
180 unsafe { ffi::SetWindowMonitor(monitor as _) }
181 }
182
183 #[inline]
185 pub fn set_window_min_size(&mut self, width: u32, height: u32) {
186 unsafe { ffi::SetWindowMinSize(width as _, height as _) }
187 }
188
189 #[inline]
191 pub fn set_window_size(&mut self, width: u32, height: u32) {
192 unsafe { ffi::SetWindowSize(width as _, height as _) }
193 }
194
195 #[inline]
197 pub fn set_window_opacity(&mut self, opacity: f32) {
198 unsafe { ffi::SetWindowOpacity(opacity) }
199 }
200
201 #[inline]
203 pub fn get_window_handle(&self) -> *mut core::ffi::c_void {
204 unsafe { ffi::GetWindowHandle() }
205 }
206
207 #[inline]
209 pub fn get_screen_width(&self) -> u32 {
210 unsafe { ffi::GetScreenWidth() as _ }
211 }
212
213 #[inline]
215 pub fn get_screen_height(&self) -> u32 {
216 unsafe { ffi::GetScreenHeight() as _ }
217 }
218
219 #[inline]
221 pub fn get_render_width(&self) -> u32 {
222 unsafe { ffi::GetRenderWidth() as _ }
223 }
224
225 #[inline]
227 pub fn get_render_height(&self) -> u32 {
228 unsafe { ffi::GetRenderHeight() as _ }
229 }
230
231 #[inline]
233 pub fn get_monitor_count(&self) -> u32 {
234 unsafe { ffi::GetMonitorCount() as _ }
235 }
236
237 #[inline]
239 pub fn get_current_monitor(&self) -> u32 {
240 unsafe { ffi::GetCurrentMonitor() as _ }
241 }
242
243 #[inline]
245 pub fn get_monitor_position(&self, monitor: u32) -> Vector2 {
246 unsafe { ffi::GetMonitorPosition(monitor as _).into() }
247 }
248
249 #[inline]
251 pub fn get_monitor_width(&self, monitor: u32) -> u32 {
252 unsafe { ffi::GetMonitorWidth(monitor as _) as _ }
253 }
254
255 #[inline]
257 pub fn get_monitor_height(&self, monitor: u32) -> u32 {
258 unsafe { ffi::GetMonitorHeight(monitor as _) as _ }
259 }
260
261 #[inline]
263 pub fn get_monitor_physical_width(&self, monitor: u32) -> u32 {
264 unsafe { ffi::GetMonitorPhysicalWidth(monitor as _) as _ }
265 }
266
267 #[inline]
269 pub fn get_monitor_physical_height(&self, monitor: u32) -> u32 {
270 unsafe { ffi::GetMonitorPhysicalHeight(monitor as _) as _ }
271 }
272
273 #[inline]
275 pub fn get_monitor_refresh_rate(&self, monitor: u32) -> u32 {
276 unsafe { ffi::GetMonitorRefreshRate(monitor as _) as _ }
277 }
278
279 #[inline]
281 pub fn get_window_position(&self) -> Vector2 {
282 unsafe { ffi::GetWindowPosition().into() }
283 }
284
285 #[inline]
287 pub fn get_window_scale_dpi(&self) -> Vector2 {
288 unsafe { ffi::GetWindowScaleDPI().into() }
289 }
290
291 #[inline]
293 pub fn get_monitor_name(&self, monitor: u32) -> String {
294 let name = unsafe { ffi::GetMonitorName(monitor as _) };
295
296 if name.is_null() {
297 String::new()
298 } else {
299 unsafe { CStr::from_ptr(name) }
300 .to_string_lossy()
301 .into_owned()
302 }
303 }
304
305 #[inline]
307 pub fn set_clipboard_text(&mut self, text: &str) {
308 let text = CString::new(text).unwrap();
309
310 unsafe { ffi::SetClipboardText(text.as_ptr()) }
311 }
312
313 #[inline]
315 pub fn get_clipboard_text(&self) -> String {
316 let text = unsafe { ffi::GetClipboardText() };
317
318 if text.is_null() {
319 String::new()
320 } else {
321 unsafe { CStr::from_ptr(text) }
322 .to_string_lossy()
323 .into_owned()
324 }
325 }
326
327 #[inline]
329 pub fn enable_event_waiting(&mut self) {
330 unsafe { ffi::EnableEventWaiting() }
331 }
332
333 #[inline]
335 pub fn disable_event_waiting(&mut self) {
336 unsafe { ffi::DisableEventWaiting() }
337 }
338
339 #[inline]
342 pub fn swap_screen_buffer(&mut self) {
343 unsafe { ffi::SwapScreenBuffer() }
344 }
345
346 #[inline]
349 pub fn poll_input_events(&mut self) {
350 unsafe { ffi::PollInputEvents() }
351 }
352
353 #[inline]
356 pub fn wait_time(&mut self, duration: Duration) {
357 unsafe { ffi::WaitTime(duration.as_secs_f64()) }
358 }
359
360 #[inline]
362 pub fn show_cursor(&mut self) {
363 unsafe { ffi::ShowCursor() }
364 }
365
366 #[inline]
368 pub fn hide_cursor(&mut self) {
369 unsafe { ffi::HideCursor() }
370 }
371
372 #[inline]
374 pub fn is_cursor_hidden(&self) -> bool {
375 unsafe { ffi::IsCursorHidden() }
376 }
377
378 #[inline]
380 pub fn enable_cursor(&mut self) {
381 unsafe { ffi::EnableCursor() }
382 }
383
384 #[inline]
386 pub fn disable_cursor(&mut self) {
387 unsafe { ffi::DisableCursor() }
388 }
389
390 #[inline]
392 pub fn is_cursor_on_screen(&self) -> bool {
393 unsafe { ffi::IsCursorOnScreen() }
394 }
395
396 #[inline]
398 pub fn set_target_fps(&mut self, fps: u32) {
399 unsafe { ffi::SetTargetFPS(fps as _) }
400 }
401
402 #[inline]
404 pub fn get_fps(&self) -> u32 {
405 unsafe { ffi::GetFPS() as _ }
406 }
407
408 #[inline]
410 pub fn get_frame_time(&self) -> Duration {
411 Duration::from_secs_f32(unsafe { ffi::GetFrameTime() })
412 }
413
414 #[inline]
416 pub fn get_time(&self) -> Duration {
417 Duration::from_secs_f64(unsafe { ffi::GetTime() })
418 }
419
420 #[inline]
422 pub fn get_random_value(&self, min: i32, max: i32) -> i32 {
423 unsafe { ffi::GetRandomValue(min, max) }
424 }
425
426 #[inline]
428 pub fn set_random_seed(&mut self, seed: u32) {
429 unsafe { ffi::SetRandomSeed(seed) }
430 }
431
432 #[inline]
434 pub fn take_screenshot(&mut self, file_name: &str) {
435 let file_name = CString::new(file_name).unwrap();
436
437 unsafe { ffi::TakeScreenshot(file_name.as_ptr()) }
438 }
439
440 #[inline]
442 pub fn open_url(&self, url: &str) {
443 let url = CString::new(url).unwrap();
444
445 unsafe { ffi::OpenURL(url.as_ptr()) }
446 }
447
448 #[inline]
450 pub fn is_file_dropped(&self) -> bool {
451 unsafe { ffi::IsFileDropped() }
452 }
453
454 #[inline]
456 pub fn get_dropped_files(&self) -> Vec<String> {
457 let path_list = unsafe { ffi::LoadDroppedFiles() };
458 let mut paths = Vec::new();
459
460 for i in 0..(path_list.count as usize) {
461 let path = unsafe { CStr::from_ptr(path_list.paths.add(i).read()) };
462
463 paths.push(path.to_string_lossy().into_owned());
464 }
465
466 unsafe {
467 ffi::UnloadDroppedFiles(path_list);
468 }
469
470 paths
471 }
472
473 #[inline]
475 pub fn is_key_pressed(&self, key: KeyboardKey) -> bool {
476 unsafe { ffi::IsKeyPressed(key as _) }
477 }
478
479 #[inline]
481 pub fn is_key_down(&self, key: KeyboardKey) -> bool {
482 unsafe { ffi::IsKeyDown(key as _) }
483 }
484
485 #[inline]
487 pub fn is_key_released(&self, key: KeyboardKey) -> bool {
488 unsafe { ffi::IsKeyReleased(key as _) }
489 }
490
491 #[inline]
493 pub fn is_key_up(&self, key: KeyboardKey) -> bool {
494 unsafe { ffi::IsKeyUp(key as _) }
495 }
496
497 #[inline]
499 pub fn set_exit_key(&mut self, key: KeyboardKey) {
500 unsafe { ffi::SetExitKey(key as _) }
501 }
502
503 #[inline]
505 pub fn get_key_pressed(&self) -> KeyboardKey {
506 unsafe { std::mem::transmute(ffi::GetKeyPressed()) }
507 }
508
509 #[inline]
511 pub fn get_char_pressed(&self) -> Option<char> {
512 let ch = unsafe { ffi::GetCharPressed() as u32 };
513
514 if ch != 0 {
515 char::from_u32(ch)
516 } else {
517 None
518 }
519 }
520
521 #[inline]
523 pub fn is_gamepad_available(&self, gamepad: u32) -> bool {
524 unsafe { ffi::IsGamepadAvailable(gamepad as _) }
525 }
526
527 #[inline]
529 pub fn get_gamepad_name(&self, gamepad: u32) -> String {
530 let name = unsafe { ffi::GetGamepadName(gamepad as _) };
531
532 if !name.is_null() {
533 let name = unsafe { CStr::from_ptr(name) };
534
535 name.to_string_lossy().into_owned()
536 } else {
537 String::new()
538 }
539 }
540
541 #[inline]
543 pub fn is_gamepad_button_pressed(&self, gamepad: u32, button: GamepadButton) -> bool {
544 unsafe { ffi::IsGamepadButtonPressed(gamepad as _, button as _) }
545 }
546
547 #[inline]
549 pub fn is_gamepad_button_down(&self, gamepad: u32, button: GamepadButton) -> bool {
550 unsafe { ffi::IsGamepadButtonDown(gamepad as _, button as _) }
551 }
552
553 #[inline]
555 pub fn is_gamepad_button_released(&self, gamepad: u32, button: GamepadButton) -> bool {
556 unsafe { ffi::IsGamepadButtonReleased(gamepad as _, button as _) }
557 }
558
559 #[inline]
561 pub fn is_gamepad_button_up(&self, gamepad: u32, button: GamepadButton) -> bool {
562 unsafe { ffi::IsGamepadButtonUp(gamepad as _, button as _) }
563 }
564
565 #[inline]
567 pub fn get_gamepad_button_pressed(&self) -> GamepadButton {
568 unsafe { std::mem::transmute(ffi::GetGamepadButtonPressed()) }
569 }
570
571 #[inline]
573 pub fn get_gamepad_axis_count(&self, gamepad: u32) -> u32 {
574 unsafe { ffi::GetGamepadAxisCount(gamepad as _) as _ }
575 }
576
577 #[inline]
579 pub fn get_gamepad_axis_movement(&self, gamepad: u32, axis: GamepadAxis) -> f32 {
580 unsafe { ffi::GetGamepadAxisMovement(gamepad as _, axis as _) }
581 }
582
583 #[inline]
585 pub fn set_gamepad_mappings(&mut self, mappings: &str) -> i32 {
586 let mappings = CString::new(mappings).unwrap();
587
588 unsafe { ffi::SetGamepadMappings(mappings.as_ptr()) }
589 }
590
591 #[inline]
593 pub fn is_mouse_button_pressed(&self, button: MouseButton) -> bool {
594 unsafe { ffi::IsMouseButtonPressed(button as _) }
595 }
596
597 #[inline]
599 pub fn is_mouse_button_down(&self, button: MouseButton) -> bool {
600 unsafe { ffi::IsMouseButtonDown(button as _) }
601 }
602
603 #[inline]
605 pub fn is_mouse_button_released(&self, button: MouseButton) -> bool {
606 unsafe { ffi::IsMouseButtonReleased(button as _) }
607 }
608
609 #[inline]
611 pub fn is_mouse_button_up(&self, button: MouseButton) -> bool {
612 unsafe { ffi::IsMouseButtonUp(button as _) }
613 }
614
615 #[inline]
617 pub fn get_mouse_x(&self) -> i32 {
618 unsafe { ffi::GetMouseX() }
619 }
620
621 #[inline]
623 pub fn get_mouse_y(&self) -> i32 {
624 unsafe { ffi::GetMouseY() }
625 }
626
627 #[inline]
629 pub fn get_mouse_position(&self) -> Vector2 {
630 unsafe { ffi::GetMousePosition().into() }
631 }
632
633 #[inline]
635 pub fn get_mouse_delta(&self) -> Vector2 {
636 unsafe { ffi::GetMouseDelta().into() }
637 }
638
639 #[inline]
641 pub fn set_mouse_position(&mut self, x: i32, y: i32) {
642 unsafe { ffi::SetMousePosition(x, y) }
643 }
644
645 #[inline]
647 pub fn set_mouse_offset(&mut self, offset_x: i32, offset_y: i32) {
648 unsafe { ffi::SetMouseOffset(offset_x, offset_y) }
649 }
650
651 #[inline]
653 pub fn set_mouse_scale(&mut self, scale_x: f32, scale_y: f32) {
654 unsafe { ffi::SetMouseScale(scale_x, scale_y) }
655 }
656
657 #[inline]
659 pub fn get_mouse_wheel_move(&self) -> f32 {
660 unsafe { ffi::GetMouseWheelMove() }
661 }
662
663 #[inline]
665 pub fn get_mouse_wheel_move_vec(&self) -> Vector2 {
666 unsafe { ffi::GetMouseWheelMoveV().into() }
667 }
668
669 #[inline]
671 pub fn set_mouse_cursor(&mut self, cursor: MouseCursor) {
672 unsafe { ffi::SetMouseCursor(cursor as _) }
673 }
674
675 #[inline]
677 pub fn get_touch_x(&self) -> i32 {
678 unsafe { ffi::GetTouchX() }
679 }
680
681 #[inline]
683 pub fn get_touch_y(&self) -> i32 {
684 unsafe { ffi::GetTouchY() }
685 }
686
687 #[inline]
689 pub fn get_touch_position(&self, index: u32) -> Vector2 {
690 unsafe { ffi::GetTouchPosition(index as _).into() }
691 }
692
693 #[inline]
695 pub fn get_touch_point_id(&self, index: u32) -> u32 {
696 unsafe { ffi::GetTouchPointId(index as _) as _ }
697 }
698
699 #[inline]
701 pub fn get_touch_point_count(&self) -> u32 {
702 unsafe { ffi::GetTouchPointCount() as _ }
703 }
704
705 #[inline]
707 pub fn set_gestures_enabled(&mut self, flags: Gesture) {
708 unsafe { ffi::SetGesturesEnabled(flags.bits()) }
709 }
710
711 #[inline]
713 pub fn is_gesture_detected(&self, gesture: Gesture) -> bool {
714 unsafe { ffi::IsGestureDetected(gesture.bits() as _) }
715 }
716
717 #[inline]
719 pub fn get_gesture_detected(&self) -> Gesture {
720 unsafe { Gesture(ffi::GetGestureDetected() as _) }
721 }
722
723 #[inline]
725 pub fn get_gesture_hold_duration(&self) -> Duration {
726 Duration::from_micros(unsafe { ffi::GetGestureHoldDuration() * 1000. } as u64)
727 }
728
729 #[inline]
731 pub fn get_gesture_drag_vector(&self) -> Vector2 {
732 unsafe { ffi::GetGestureDragVector().into() }
733 }
734
735 #[inline]
737 pub fn get_gesture_drag_angle(&self) -> f32 {
738 unsafe { ffi::GetGestureDragAngle() }
739 }
740
741 #[inline]
743 pub fn get_gesture_pinch_vector(&self) -> Vector2 {
744 unsafe { ffi::GetGesturePinchVector().into() }
745 }
746
747 #[inline]
749 pub fn get_gesture_pinch_angle(&self) -> f32 {
750 unsafe { ffi::GetGesturePinchAngle() }
751 }
752
753 #[inline]
755 pub fn begin_drawing(&mut self) -> DrawHandle {
756 unsafe {
757 ffi::BeginDrawing();
758 }
759
760 DrawHandle(self)
761 }
762
763 #[inline]
765 pub fn set_trace_log_level(&mut self, level: TraceLogLevel) {
766 unsafe { ffi::SetTraceLogLevel(level as _) }
767 }
768}
769
770impl Drop for Raylib {
771 #[inline]
772 fn drop(&mut self) {
773 unsafe { ffi::CloseWindow() }
774 }
775}