raylib/core/
mod.rs

1#[macro_use]
2mod macros;
3
4pub mod audio;
5pub mod automation;
6pub mod callbacks;
7pub mod camera;
8pub mod collision;
9pub mod color;
10pub mod data;
11pub mod drawing;
12pub mod error;
13pub mod file;
14
15pub mod input;
16pub mod logging;
17pub mod math;
18pub mod misc;
19pub mod models;
20pub mod shaders;
21pub mod text;
22pub mod texture;
23pub mod vr;
24pub mod window;
25
26use raylib_sys::TraceLogLevel;
27
28use crate::ffi;
29use std::ffi::CString;
30use std::marker::PhantomData;
31
32// shamelessly stolen from imgui
33#[macro_export]
34macro_rules! rstr {
35    ($e:tt) => ({
36        #[allow(unused_unsafe)]
37        unsafe {
38          std::ffi::CStr::from_bytes_with_nul_unchecked(concat!($e, "\0").as_bytes())
39        }
40    });
41    ($e:tt, $($arg:tt)*) => ({
42        #[allow(unused_unsafe)]
43        unsafe {
44          std::ffi::CString::new(format!($e, $($arg)*)).unwrap()
45        }
46    })
47}
48
49/// This token is used to ensure certain functions are only running on the same
50/// thread raylib was initialized from. This is useful for architectures like macos
51/// where cocoa can only be called from one thread.
52#[derive(Clone, Debug)]
53pub struct RaylibThread(PhantomData<*const ()>);
54
55/// The main interface into the Raylib API.
56///
57/// This is the way in which you will use the vast majority of Raylib's functionality. A `RaylibHandle` can be constructed using the [`init_window`] function or through a [`RaylibBuilder`] obtained with the [`init`] function.
58///
59/// [`init_window`]: fn.init_window.html
60/// [`RaylibBuilder`]: struct.RaylibBuilder.html
61/// [`init`]: fn.init.html
62#[derive(Debug)]
63pub struct RaylibHandle(()); // inner field is private, preventing manual construction
64
65impl Drop for RaylibHandle {
66    fn drop(&mut self) {
67        unsafe {
68            if ffi::IsWindowReady() {
69                ffi::CloseWindow();
70                // NOTE(IOI_XD): If imgui is enabled, we don't call the destructor here because we're using a context that Rust expects to free, and the only other thing in that function is the free'ing of FontTexture...an action which causes a segfault.
71                // It then gets successfully replaced if rlImGuiReloadFonts is called, so we'll take it.
72            }
73        }
74    }
75}
76
77/// A builder that allows more customization of the game window shown to the user before the `RaylibHandle` is created.
78#[derive(Debug, Default)]
79pub struct RaylibBuilder {
80    fullscreen_mode: bool,
81    window_resizable: bool,
82    window_undecorated: bool,
83    window_transparent: bool,
84    msaa_4x_hint: bool,
85    vsync_hint: bool,
86    log_level: TraceLogLevel,
87    width: i32,
88    height: i32,
89    title: String,
90    #[cfg(feature = "imgui")]
91    imgui_theme: crate::imgui::ImGuiTheme,
92}
93
94/// Creates a `RaylibBuilder` for choosing window options before initialization.
95pub fn init() -> RaylibBuilder {
96    RaylibBuilder {
97        width: 640,
98        height: 480,
99        title: "raylib-rs".to_string(),
100        ..Default::default()
101    }
102}
103
104impl RaylibBuilder {
105    /// Sets the window to be fullscreen.
106    pub fn fullscreen(&mut self) -> &mut Self {
107        self.fullscreen_mode = true;
108        self
109    }
110
111    /// Set the builder's log level.
112    pub fn log_level(&mut self, level: TraceLogLevel) -> &mut Self {
113        self.log_level = level;
114        self
115    }
116    /// Sets the window to be resizable.
117    pub fn resizable(&mut self) -> &mut Self {
118        self.window_resizable = true;
119        self
120    }
121
122    /// Sets the window to be undecorated (without a border).
123    pub fn undecorated(&mut self) -> &mut Self {
124        self.window_undecorated = true;
125        self
126    }
127
128    /// Sets the window to be transparent.
129    pub fn transparent(&mut self) -> &mut Self {
130        self.window_transparent = true;
131        self
132    }
133
134    /// Hints that 4x MSAA (anti-aliasing) should be enabled. The system's graphics drivers may override this setting.
135    pub fn msaa_4x(&mut self) -> &mut Self {
136        self.msaa_4x_hint = true;
137        self
138    }
139
140    /// Hints that vertical sync (VSync) should be enabled. The system's graphics drivers may override this setting.
141    pub fn vsync(&mut self) -> &mut Self {
142        self.vsync_hint = true;
143        self
144    }
145
146    /// Sets the window's width.
147    pub fn width(&mut self, w: i32) -> &mut Self {
148        self.width = w;
149        self
150    }
151
152    /// Sets the window's height.
153    pub fn height(&mut self, h: i32) -> &mut Self {
154        self.height = h;
155        self
156    }
157
158    /// Sets the window's width and height.
159    pub fn size(&mut self, w: i32, h: i32) -> &mut Self {
160        self.width = w;
161        self.height = h;
162        self
163    }
164
165    /// Sets the window title.
166    pub fn title(&mut self, text: &str) -> &mut Self {
167        self.title = text.to_string();
168        self
169    }
170
171    #[cfg(feature = "imgui")]
172    /// Set the theme to be used for imgui.
173    pub fn imgui_theme(&mut self, theme: crate::imgui::ImGuiTheme) -> &mut Self {
174        self.imgui_theme = theme;
175        self
176    }
177
178    /// Builds and initializes a Raylib window.
179    ///
180    /// # Panics
181    ///
182    /// Attempting to initialize Raylib more than once will result in a panic.
183    pub fn build(&self) -> (RaylibHandle, RaylibThread) {
184        use crate::consts::ConfigFlags::*;
185        let mut flags = 0u32;
186        if self.fullscreen_mode {
187            flags |= FLAG_FULLSCREEN_MODE as u32;
188        }
189        if self.window_resizable {
190            flags |= FLAG_WINDOW_RESIZABLE as u32;
191        }
192        if self.window_undecorated {
193            flags |= FLAG_WINDOW_UNDECORATED as u32;
194        }
195        if self.window_transparent {
196            flags |= FLAG_WINDOW_TRANSPARENT as u32;
197        }
198        if self.msaa_4x_hint {
199            flags |= FLAG_MSAA_4X_HINT as u32;
200        }
201        if self.vsync_hint {
202            flags |= FLAG_VSYNC_HINT as u32;
203        }
204
205        unsafe {
206            ffi::SetConfigFlags(flags as u32);
207        }
208
209        unsafe {
210            ffi::SetTraceLogLevel(self.log_level as i32);
211        }
212
213        let rl = init_window(self.width, self.height, &self.title);
214
215        #[cfg(feature = "imgui")]
216        unsafe {
217            crate::imgui::init_imgui_context(self.imgui_theme == crate::imgui::ImGuiTheme::Dark);
218        }
219
220        (rl, RaylibThread(PhantomData))
221    }
222}
223
224/// Initializes window and OpenGL context.
225///
226/// # Panics
227///
228/// Attempting to initialize Raylib more than once will result in a panic.
229fn init_window(width: i32, height: i32, title: &str) -> RaylibHandle {
230    if unsafe { ffi::IsWindowReady() } {
231        panic!("Attempted to initialize raylib-rs more than once!");
232    } else {
233        unsafe {
234            let c_title = CString::new(title).unwrap();
235            ffi::InitWindow(width, height, c_title.as_ptr());
236        }
237        if !unsafe { ffi::IsWindowReady() } {
238            panic!("Attempting to create window failed!");
239        }
240
241        RaylibHandle(())
242    }
243}