Skip to main content

flake/
prelude.rs

1#![allow(unused)]
2
3//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4
5pub use crate::camera::camera2d::Camera2D;
6pub use crate::camera::render_target::RenderTarget;
7use crate::draw_state::shapes::Shape;
8pub use crate::draw_state::shapes::color::*;
9pub use crate::end_frame;
10use crate::global::{PENDING_CONFIG, STATE, ctx};
11pub use crate::misc::flake_image::Image;
12use crate::misc::font::Font;
13pub use crate::misc::math::*;
14pub use crate::misc::rect::Rect;
15use crate::misc::span::RichtextSection;
16pub use crate::misc::span::Span;
17pub use crate::misc::timer::Timer;
18pub use crate::misc::*;
19use crate::model::instance::Instance;
20pub use crate::model::texture::DrawTextureParams;
21pub use crate::model::texture::FilterType;
22use crate::model::texture::{GpuTexture, Texture};
23pub use crate::runtime::next_frame::next_frame;
24pub use crate::{FlakeResult, flake};
25use image::{DynamicImage, GenericImageView, ImageBuffer, Rgb, Rgba};
26use std::borrow::Borrow;
27use std::sync::Arc;
28pub use winit::event::MouseButton;
29pub use winit::keyboard::KeyCode;
30#[cfg(target_os = "windows")]
31use winit::platform::windows::WindowExtWindows;
32use winit::window::Window;
33pub use winit::window::{CursorIcon, WindowButtons, WindowLevel};
34// -- Out-facing API --------------------------------------------------------------------------------------------------------------
35
36/// Exits the running application, must be called while running.
37///
38/// # Examples
39///
40/// ```
41/// flake_quit();
42/// ```
43pub fn flake_quit() {
44    ctx(|s| s.exit())
45}
46
47/// Sleeps (waits) for a set amount of seconds.
48/// (Will pause the window thread as well)
49/// App may become "not responding" if time is too high.
50/// Good for games like tetris/snake.
51///
52/// # Examples
53///
54/// ```
55/// flake_sleep(0.1);
56/// ```
57pub fn flake_sleep(seconds: f32) {
58    std::thread::sleep(std::time::Duration::from_secs_f32(seconds));
59}
60
61/// Creates a `Timer` whose time goes down each frame. Can be paused. Check `Timer` docs for more info.
62///
63/// # Examples
64///
65/// ```
66/// let mut my_timer = add_timer(Timer::new(5.0));
67///
68/// my_timer.on_completed(|| {
69///     println!("Timer got completed");
70/// });
71/// ```
72pub fn add_timer(timer: Timer) -> Timer {
73    if STATE.get().is_some() {
74        return ctx(|s| {
75            if !s.timers.contains(&timer) {
76                s.add_timer(timer.clone());
77            }
78            timer
79        });
80    }
81
82    PENDING_CONFIG.with_borrow_mut(|s| {
83        if !s.timers.contains(&timer) {
84            s.timers.push(timer.clone())
85        }
86    });
87
88    timer
89}
90
91/// Gets the winit window used by the application
92///
93/// # Examples
94///
95/// ```
96/// let win = get_window();
97/// win.set_transparent(true);
98/// ```
99pub fn get_window() -> Arc<Window> {
100    ctx(|s| s.get_window())
101}
102
103/// Sets whether window catches mouse events.
104pub fn set_window_passthrough(passthrough: bool) {
105    if STATE.get().is_some() {
106        return ctx(|s| s.set_window_passthrough(passthrough));
107    }
108
109    PENDING_CONFIG.with_borrow_mut(|s| s.window_passthrough = Some(passthrough));
110}
111
112/// Sets whether the window is AlwaysOnTop, AlwaysOnBottom, or Normal
113pub fn set_window_level(level: WindowLevel) {
114    if STATE.get().is_some() {
115        return ctx(|s| s.set_window_level(level));
116    }
117
118    PENDING_CONFIG.with_borrow_mut(|s| s.window_level = Some(level));
119}
120
121/// Sets which window buttons are enabled. Any button not included is disabled
122/// (e.g. `WindowButtons::CLOSE` leaves only the close button).
123pub fn set_window_enabled_buttons(window_buttons: WindowButtons) {
124    ctx(|s| s.get_window().set_enabled_buttons(window_buttons));
125}
126
127/// Sets whether the app is shown or not shown (skipped) in the taskbar
128pub fn set_skip_taskbar(skip: bool) {
129    if STATE.get().is_some() {
130        #[cfg(target_os = "windows")]
131        return ctx(|s| s.window.set_skip_taskbar(skip));
132    }
133
134    PENDING_CONFIG.with_borrow_mut(|s| s.skip_taskbar = Some(skip));
135}
136
137/// Sets whether the window is transparent.
138/// **Run this before `flake::run()`** as it might not work after the window has been created.
139pub fn set_window_transparent(transparent: bool) {
140    if STATE.get().is_some() {
141        return get_window().set_transparent(transparent);
142    }
143
144    PENDING_CONFIG.with_borrow_mut(|s| s.window_transparent = Some(transparent));
145}
146
147/// Sets whether the window decorations (titlebar, border, etc.) are enabled
148pub fn set_window_decorations(enabled: bool) {
149    if STATE.get().is_some() {
150        return get_window().set_decorations(enabled);
151    }
152
153    PENDING_CONFIG.with_borrow_mut(|s| s.window_decorations = Some(enabled));
154}
155
156// -- Window --------------------------------------------------------------------------------------------------------------
157
158/// Sets the title of the window.
159///
160/// # Examples
161///
162/// ```
163/// set_window_title("Hello");
164/// ```
165pub fn set_window_title(title: &str) {
166    if STATE.get().is_some() {
167        return ctx(|s| s.set_window_title(title));
168    }
169
170    PENDING_CONFIG.with_borrow_mut(|s| s.window_title = Some(title.into()));
171}
172
173/// Sets whether the window is visible or not.
174///
175/// # Examples
176///
177/// ```
178/// set_window_visible(false); // hides the window
179/// set_window_visible(true); // shows the window
180/// ```
181pub fn set_window_visible(visible: bool) {
182    if STATE.get().is_some() {
183        return ctx(|s| s.set_window_visible(visible));
184    }
185
186    PENDING_CONFIG.with_borrow_mut(|s| s.window_visible = Some(visible));
187}
188
189/// Sets the icon of the window.
190///
191/// # Examples
192///
193/// ```
194/// set_window_icon("path_to_icon");
195/// ```
196pub fn set_window_icon(path: &str) {
197    let img = image::open(path)
198        .expect("image icon does not exist at path")
199        .into_rgba8();
200    let (width, height) = img.dimensions();
201    let rgba = img.into_raw();
202
203    if STATE.get().is_some() {
204        return ctx(|s| s.set_window_icon(rgba, width, height));
205    }
206
207    PENDING_CONFIG.with_borrow_mut(|s| s.window_icon = Some((rgba, width, height)));
208}
209
210/// Sets the window icon from encoded image bytes (PNG, etc.). Panics if the bytes aren't a valid image.
211pub fn set_window_icon_bytes(bytes: &[u8]) {
212    let img = image::load_from_memory(bytes)
213        .expect("image icon does not exist at path")
214        .into_rgba8();
215    let (width, height) = img.dimensions();
216    let rgba = img.into_raw();
217
218    if STATE.get().is_some() {
219        return ctx(|s| s.set_window_icon(rgba, width, height));
220    }
221
222    PENDING_CONFIG.with_borrow_mut(|s| s.window_icon = Some((rgba, width, height)));
223}
224
225/// Sets position X of the window.
226///
227/// # Examples
228///
229/// ```
230/// set_window_x(500);
231/// ```
232pub fn set_window_x(x: i32) {
233    if STATE.get().is_some() {
234        return ctx(|s| s.set_window_x(x));
235    }
236
237    PENDING_CONFIG.with_borrow_mut(|s| s.window_x = Some(x));
238}
239
240/// Sets position Y of the window.
241///
242/// # Examples
243///
244/// ```
245/// set_window_y(500);
246/// ```
247pub fn set_window_y(y: i32) {
248    if STATE.get().is_some() {
249        return ctx(|s| s.set_window_y(y));
250    }
251
252    PENDING_CONFIG.with_borrow_mut(|s| s.window_y = Some(y));
253}
254
255/// Sets position of the window.
256///
257/// # Examples
258///
259/// ```
260/// set_window_position(500, 500);
261/// ```
262pub fn set_window_position(x: i32, y: i32) {
263    set_window_x(x);
264    set_window_y(y);
265}
266
267/// Gets width of the window
268pub fn window_width() -> f32 {
269    ctx(|s| s.window_width())
270}
271
272/// Gets height of the window
273pub fn window_height() -> f32 {
274    ctx(|s| s.window_height())
275}
276
277/// Gets size of the window
278pub fn window_size() -> Vector2 {
279    ctx(|s| Vector2::new(s.window_width(), s.window_height()))
280}
281
282/// Gets position of the window
283pub fn window_position() -> (f32, f32) {
284    ctx(|s| s.window_position())
285}
286
287/// Gets position of the window as Vector2<f32>
288pub fn window_position_vec2() -> Vector2 {
289    ctx(|s| s.window_position().into())
290}
291
292/// Gets X position of the window
293pub fn window_x() -> f32 {
294    ctx(|s| s.window_x())
295}
296
297/// Gets Y position of the window
298pub fn window_y() -> f32 {
299    ctx(|s| s.window_y())
300}
301
302/// Sets width of the window.
303///
304/// # Examples
305///
306/// ```
307/// set_window_width(500);
308/// ```
309pub fn set_window_width(w: u32) {
310    if STATE.get().is_some() {
311        return ctx(|s| s.set_window_w(w));
312    }
313
314    PENDING_CONFIG.with_borrow_mut(|s| s.window_width = Some(w));
315}
316
317/// Sets height of the window.
318///
319/// # Examples
320///
321/// ```
322/// set_window_height(500);
323/// ```
324pub fn set_window_height(h: u32) {
325    if STATE.get().is_some() {
326        return ctx(|s| s.set_window_h(h));
327    }
328
329    PENDING_CONFIG.with_borrow_mut(|s| s.window_height = Some(h));
330}
331
332/// Sets size of the window.
333///
334/// # Examples
335///
336/// ```
337/// set_window_size(500, 500);
338/// ```
339pub fn set_window_size(w: u32, h: u32) {
340    if STATE.get().is_some() {
341        return ctx(|s| s.set_window_size(w, h));
342    }
343
344    PENDING_CONFIG.with_borrow_mut(|s| {
345        s.window_width = Some(w);
346        s.window_height = Some(h);
347    });
348}
349
350/// Sets whether the window can be resized using the resize handles.
351pub fn set_window_resizable(resizeable: bool) {
352    ctx(|s| s.window.set_resizable(resizeable));
353}
354
355// -- TIME --------------------------------------------------------------------------------------------------------------
356
357/// Gets the frames per second of the application.
358/// (Limited by target framerate & fps cap). Uncap the FPS using `set_fps_capped(false)`.
359///
360/// # Examples
361///
362/// ```
363/// println!("{}", get_fps());
364/// ```
365pub fn get_fps() -> f32 {
366    ctx(|s| s.get_fps())
367}
368
369/// Sets target FPS of the application (Uses screen refresh rate by default).
370///
371/// # Examples
372///
373/// ```
374/// set_target_fps(60);
375/// ```
376pub fn set_target_fps(fps: usize) {
377    if STATE.get().is_some() {
378        return ctx(|s| s.set_target_fps(fps));
379    }
380
381    PENDING_CONFIG.with_borrow_mut(|s| s.target_fps = Some(fps));
382}
383
384/// Caps/unlocks the FPS of the application. (Capped by default)
385///
386/// # Examples
387///
388/// ```
389/// set_fps_capped(false); // uncaps the FPS
390/// set_fps_capped(true); // caps the FPS to target FPS
391/// ```
392pub fn set_fps_capped(capped: bool) {
393    if STATE.get().is_some() {
394        return ctx(|s| s.set_fps_capped(capped));
395    }
396
397    PENDING_CONFIG.with_borrow_mut(|s| s.fps_capped = Some(capped));
398}
399
400/// Gets the time taken since last frame in seconds.
401///
402/// # Examples
403///
404/// ```
405/// println!("{}", get_frame_time());
406/// ```
407
408pub fn get_frame_time() -> f32 {
409    ctx(|s| s.get_frame_time())
410}
411
412/// Gets the amount of frames that have gone by since the start of the application.
413///
414/// # Examples
415///
416/// ```
417/// println!("{}", get_frames());
418/// ```
419
420pub fn get_frames() -> usize {
421    ctx(|s| s.get_frames())
422}
423
424// -- INPUT --------------------------------------------------------------------------------------------------------------
425
426/// Returns the window-relative mouse x and y position in a tuple.
427///
428/// # Examples
429///
430/// ```
431/// let (mx, my) = mouse_position();
432/// ```
433pub fn mouse_position() -> (f32, f32) {
434    ctx(|s| s.mouse_state.get_position().into())
435}
436
437/// Returns the window-relative mouse x and y position in a `Vector2`.
438///
439/// # Examples
440///
441/// ```
442/// let pos = mouse_position_vec2();
443/// println!("{}, {}", pos.x, pos.y);
444/// ```
445pub fn mouse_position_vec2() -> Vector2 {
446    ctx(|s| s.mouse_state.get_position())
447}
448
449/// Returns the mouse x and y position on the screen instead of window-relative as Vector2.
450pub fn mouse_screen_position_vec2() -> Vector2 {
451    ctx(|s| s.mouse_state.get_screen_position())
452}
453
454/// Returns the mouse x and y position on the screen instead of window-relative.
455pub fn mouse_screen_position() -> (f32, f32) {
456    ctx(|s| s.mouse_state.get_screen_position().into())
457}
458
459/// Returns the mouse scroll direction this frame (line delta).
460/// (You might need to multiply this by something like 20).
461///
462/// # Examples
463///
464/// ```
465/// let scroll_y = mouse_wheel().y;
466/// ```
467pub fn mouse_wheel() -> Vector2 {
468    ctx(|s| s.mouse_state.get_mouse_wheel())
469}
470
471/// Set the mouse cursor icon.
472///
473/// ## Examples
474///
475/// ```
476/// set_mouse_icon(CursorIcon::Pointer)
477/// ```
478pub fn set_mouse_icon(cursor_icon: CursorIcon) {
479    ctx(|s| s.window.set_cursor(cursor_icon))
480}
481/// Requests keyboard focus for the window.
482pub fn focus_window() {
483    get_window().focus_window();
484}
485
486/// Checks if a `MouseButton` is being held.
487///
488/// # Examples
489///
490/// ```
491/// if is_mouse_button_down(MouseButton::Left) {
492///     println!("Left mouse button is being held");
493/// }
494/// ```
495
496pub fn is_mouse_button_down(btn: MouseButton) -> bool {
497    ctx(|s| s.mouse_state.is_button_down(btn))
498}
499
500/// Checks if a `MouseButton` was just clicked this frame.
501///
502/// # Examples
503///
504/// ```
505/// if is_mouse_button_pressed(MouseButton::Left) {
506///     println!("User clicked left mouse button once");
507/// }
508/// ```
509pub fn is_mouse_button_pressed(btn: MouseButton) -> bool {
510    ctx(|s| s.mouse_state.is_button_pressed(btn))
511}
512
513/// Checks if a `MouseButton` was just released this frame.
514///
515/// # Examples
516///
517/// ```
518/// if is_mouse_button_released(MouseButton::Left) {
519///     println!("User let go of left mouse button once");
520/// }
521/// ```
522
523pub fn is_mouse_button_released(btn: MouseButton) -> bool {
524    ctx(|s| s.mouse_state.is_button_released(btn))
525}
526
527/// Checks if a key on the keyboard is being held.
528///
529/// # Examples
530///
531/// ```
532/// println!("is Space being held: {}", is_key_down(KeyCode::Space));
533/// ```
534
535pub fn is_key_down(key: KeyCode) -> bool {
536    ctx(|s| s.keyboard_state.is_key_down(key))
537}
538
539/// Checks if a key on the keyboard was just clicked.
540///
541/// # Examples
542///
543/// ```
544/// if is_key_pressed(KeyCode::Space) {
545///     println!("User clicked Space once");
546/// }
547/// ```
548pub fn is_key_pressed(key: KeyCode) -> bool {
549    ctx(|s| s.keyboard_state.is_key_pressed(key))
550}
551
552/// Checks if a key on the keyboard was just released.
553///
554/// # Examples
555///
556/// ```
557/// if is_key_released(KeyCode::Space) {
558///     println!("User let go of Space");
559/// }
560/// ```
561pub fn is_key_released(key: KeyCode) -> bool {
562    ctx(|s| s.keyboard_state.is_key_released(key))
563}
564
565/// Returns -1.0 if only `left` is held, 1.0 if only `right` is held, otherwise 0.0.
566pub fn get_axis(left: KeyCode, right: KeyCode) -> f32 {
567    ctx(|s| match (is_key_down(left), is_key_down(right)) {
568        (true, false) => -1.0,
569        (false, true) => 1.0,
570        _ => 0.0,
571    })
572}
573
574/// Returns a direction from four keys. Up is -1.0 on Y (screen coordinates).
575/// The result is not normalized, so diagonals have length √2.
576pub fn get_vector(left: KeyCode, right: KeyCode, up: KeyCode, down: KeyCode) -> Vector2 {
577    ctx(|s| {
578        Vector2::new(
579            match (is_key_down(left), is_key_down(right)) {
580                (true, false) => -1.0,
581                (false, true) => 1.0,
582                _ => 0.0,
583            },
584            match (is_key_down(up), is_key_down(down)) {
585                (true, false) => -1.0,
586                (false, true) => 1.0,
587                _ => 0.0,
588            },
589        )
590    })
591}
592
593// -- DRAWING --------------------------------------------------------------------------------------------------------------
594
595/// Clears the background using a color.
596///
597/// # Examples
598///
599/// ```
600/// clear_background(RED);
601/// ```
602
603pub fn clear_background(color: Color) {
604    if STATE.get().is_some() {
605        return ctx(|s| {
606            s.clear_color = Some(color);
607            s.draw_state.clear();
608        });
609    }
610
611    PENDING_CONFIG.with_borrow_mut(|c| c.window_clear_color = Some(color));
612}
613
614/// Draws a filled rectangle with its top-left corner at `(x, y)`.
615///
616/// # Examples
617///
618/// ```
619/// draw_rectangle(100.0, 100.0, 50.0, 80.0, RED);
620/// ```
621
622pub fn draw_rectangle(x: f32, y: f32, w: f32, h: f32, color: Color) {
623    draw_rectangle_rounded(x, y, w, h, 0.0, color);
624}
625
626/// Draws a **rounded**, filled rectangle with its top-left corner at `(x, y)`.
627/// All corners have the same radius. Use `draw_rectangle_rounded_ex()` to set all the radii separately.
628///
629/// # Examples
630///
631/// ```
632/// draw_rectangle_rounded(100.0, 100.0, 50.0, 80.0, 20.0, RED); // 20.0 is the radius of each corner
633/// ```
634pub fn draw_rectangle_rounded(x: f32, y: f32, w: f32, h: f32, radius: f32, color: Color) {
635    draw_rectangle_rounded_ex(x, y, w, h, radius, radius, radius, radius, color)
636}
637
638/// Draws a **rounded**, filled rectangle with its top-left corner at `(x, y)`
639/// with the ability to set each corner's radius manually.
640///
641/// # Examples
642///
643/// ```
644/// draw_rectangle_rounded_ex(
645///     x, y,
646///     w, h,
647///     top_left, top_right,
648///     bottom_left, bottom_right,
649///     RED
650/// );
651/// ```
652pub fn draw_rectangle_rounded_ex(
653    x: f32,
654    y: f32,
655    w: f32,
656    h: f32,
657    top_left: f32,
658    top_right: f32,
659    bottom_left: f32,
660    bottom_right: f32,
661    color: Color,
662) {
663    ctx(|s| {
664        s.draw_state.draw_rectangle(
665            x,
666            y,
667            w,
668            h,
669            top_left,
670            top_right,
671            bottom_left,
672            bottom_right,
673            color,
674        )
675    });
676}
677
678/// Draws a filled rectangle using a `Rect`.
679///
680/// # Examples
681///
682/// ```
683/// draw_rectangle_from_rect(rect, RED);
684/// ```
685pub fn draw_rectangle_from_rect(rect: Rect, color: Color) {
686    draw_rectangle(rect.x, rect.y, rect.w, rect.h, color);
687}
688
689/// Draws a **rounded**, filled rectangle using a `Rect` where all corners have the same radius.
690/// Use `draw_rectangle_rounded_from_rect_ex()` to set all radii separately.
691///
692/// # Examples
693///
694/// ```
695/// draw_rectangle_rounded_from_rect(rect, 20.0, RED); // 20.0 is the radius
696/// ```
697pub fn draw_rectangle_rounded_from_rect(rect: Rect, radius: f32, color: Color) {
698    draw_rectangle_rounded(rect.x, rect.y, rect.w, rect.h, radius, color);
699}
700
701/// Draws **rounded**, outlines of a rectangle using a `Rect` where all corners have the same radius.
702/// Use `draw_rectangle_lines_rounded_from_rect_ex()` to set all radii separately.
703///
704/// # Examples
705///
706/// ```
707/// draw_rectangle_lines_rounded_from_rect(rect, 20.0, RED); // 20.0 is the radius
708/// ```
709pub fn draw_rectangle_lines_rounded_from_rect(
710    rect: Rect,
711    radius: f32,
712    thickness: f32,
713    color: Color,
714) {
715    draw_rectangle_lines_rounded(rect.x, rect.y, rect.w, rect.h, radius, thickness, color);
716}
717
718/// Draws **rounded**, outlines of a rectangle using a `Rect` where all corners have the same radius.
719/// Use `draw_rectangle_lines_rounded_from_rect_ex()` to set all radii separately.
720///
721/// # Examples
722///
723/// ```
724/// draw_rectangle_lines_rounded_from_rect(rect, 20.0, RED); // 20.0 is the radius
725/// ```
726pub fn draw_rectangle_lines_rounded_from_rect_ex(
727    rect: Rect,
728    top_left: f32,
729    top_right: f32,
730    bottom_left: f32,
731    bottom_right: f32,
732    thickness: f32,
733    color: Color,
734) {
735    draw_rectangle_lines_rounded_ex(
736        rect.x,
737        rect.y,
738        rect.w,
739        rect.h,
740        top_left,
741        top_right,
742        bottom_left,
743        bottom_right,
744        thickness,
745        color,
746    );
747}
748
749/// Draws a **rounded**, filled rectangle using a `Rect`,
750/// with the ability to set each corner's radius separately.
751///
752/// # Examples
753///
754/// ```
755/// draw_rectangle_rounded_from_rect_ex(
756///     rect,
757///     top_left, top_right,
758///     bottom_left, bottom_right,
759///     RED
760/// );
761/// ```
762pub fn draw_rectangle_rounded_from_rect_ex(
763    rect: Rect,
764    top_left: f32,
765    top_right: f32,
766    bottom_left: f32,
767    bottom_right: f32,
768    color: Color,
769) {
770    draw_rectangle_rounded_ex(
771        rect.x,
772        rect.y,
773        rect.w,
774        rect.h,
775        top_left,
776        top_right,
777        bottom_left,
778        bottom_right,
779        color,
780    );
781}
782
783/// Draws the outline of a rectangle with its top-left corner at `(x, y)`.
784///
785/// # Examples
786///
787/// ```
788/// draw_rectangle_lines(100.0, 100.0, 50.0, 80.0, 4.0, WHITE);
789/// ```
790pub fn draw_rectangle_lines(x: f32, y: f32, w: f32, h: f32, thickness: f32, color: Color) {
791    draw_rectangle_lines_rounded(x, y, w, h, 0.0, thickness, color)
792}
793
794/// Draws the outline of a rectangle using a `Rect`.
795///
796/// # Examples
797///
798/// ```
799/// draw_rectangle_lines_from_rect(rect, 4.0, WHITE);
800/// ```
801pub fn draw_rectangle_lines_from_rect(rect: Rect, thickness: f32, color: Color) {
802    draw_rectangle_lines(rect.x, rect.y, rect.w, rect.h, thickness, color);
803}
804
805/// Draws the outline of a **rounded** rectangle with its top-left corner at `(x, y)`.
806/// All corners have the same radius. The stroke is centered on the rectangle's edge.
807/// Use `draw_rectangle_lines_rounded_ex()` to set each corner's radius separately.
808///
809/// # Examples
810///
811/// ```
812/// draw_rectangle_lines_rounded(100.0, 100.0, 50.0, 80.0, 12.0, 3.0, WHITE);
813/// // radius = 12.0, thickness = 3.0
814/// ```
815pub fn draw_rectangle_lines_rounded(
816    x: f32,
817    y: f32,
818    w: f32,
819    h: f32,
820    radius: f32,
821    thickness: f32,
822    color: Color,
823) {
824    draw_rectangle_lines_rounded_ex(x, y, w, h, radius, radius, radius, radius, thickness, color);
825}
826
827/// Draws the outline of a **rounded** rectangle with its top-left corner at `(x, y)`,
828/// with the ability to set each corner's radius separately.
829/// Radii are clamped to half the shorter side.
830///
831/// # Examples
832///
833/// ```
834/// draw_rectangle_lines_rounded_ex(
835///     100.0, 100.0, 50.0, 80.0,
836///     20.0, 0.0,   // top_left, top_right
837///     0.0, 20.0,   // bottom_left, bottom_right
838///     3.0, WHITE,  // thickness, color
839/// );
840/// ```
841pub fn draw_rectangle_lines_rounded_ex(
842    x: f32,
843    y: f32,
844    w: f32,
845    h: f32,
846    top_left: f32,
847    top_right: f32,
848    bottom_left: f32,
849    bottom_right: f32,
850    thickness: f32,
851    color: Color,
852) {
853    ctx(|s| {
854        s.draw_state.draw_rectangle_lines(
855            x,
856            y,
857            w,
858            h,
859            top_left,
860            top_right,
861            bottom_left,
862            bottom_right,
863            thickness,
864            color,
865        )
866    });
867}
868
869/// Draws a filled rectangle of size `w` x `h` centered at `(x, y)`,
870/// rotated by `rotation` radians around that center.
871///
872/// # Examples
873///
874/// ```
875/// draw_rectangle_rotated(200.0, 200.0, 50.0, 80.0, std::f32::consts::FRAC_PI_4, GREEN);
876/// ```
877pub fn draw_rectangle_rotated(x: f32, y: f32, w: f32, h: f32, rotation: f32, color: Color) {
878    ctx(|s| {
879        s.draw_state
880            .draw_rectangle_rotated(x, y, w, h, rotation, 0.0, 0.0, 0.0, 0.0, color)
881    });
882}
883
884/// Draws the outline of a rectangle with its top-left corner at `(x, y)` (before rotation),
885/// rotated by `rotation` radians around its center.
886pub fn draw_rectangle_lines_rotated(
887    x: f32,
888    y: f32,
889    w: f32,
890    h: f32,
891    rotation: f32,
892    thickness: f32,
893    color: Color,
894) {
895    ctx(|s| {
896        s.draw_state.draw_rectangle_lines_rotated(
897            x, y, w, h, rotation, 0.0, 0.0, 0.0, 0.0, thickness, color,
898        )
899    });
900}
901
902/// Draws a rounded, filled rectangle centered at `(x, y)`,
903/// rotated by `rotation` radians around that center.
904/// All corners have the same radius.
905pub fn draw_rectangle_rounded_rotated(
906    x: f32,
907    y: f32,
908    w: f32,
909    h: f32,
910    rotation: f32,
911    radius: f32,
912    color: Color,
913) {
914    draw_rectangle_rounded_rotated_ex(x, y, w, h, rotation, radius, radius, radius, radius, color);
915}
916
917pub fn draw_rectangle_rounded_rotated_ex(
918    x: f32,
919    y: f32,
920    w: f32,
921    h: f32,
922    rotation: f32,
923    top_left: f32,
924    top_right: f32,
925    bottom_left: f32,
926    bottom_right: f32,
927    color: Color,
928) {
929    ctx(|s| {
930        s.draw_state.draw_rectangle_rotated(
931            x,
932            y,
933            w,
934            h,
935            rotation,
936            top_left,
937            top_right,
938            bottom_left,
939            bottom_right,
940            color,
941        )
942    });
943}
944
945/// Draws the outline of a rounded rectangle centered at `(x, y)`,
946/// rotated by `rotation` radians around that center.
947/// All corners have the same radius.
948pub fn draw_rectangle_lines_rounded_rotated(
949    x: f32,
950    y: f32,
951    w: f32,
952    h: f32,
953    rotation: f32,
954    radius: f32,
955    thickness: f32,
956    color: Color,
957) {
958    draw_rectangle_lines_rounded_rotated_ex(
959        x, y, w, h, rotation, radius, radius, radius, radius, thickness, color,
960    );
961}
962
963/// Draws the outline of a rounded rectangle centered at `(x, y)`,
964/// rotated by `rotation` radians around that center.
965/// Can set each corner's radius separately.
966pub fn draw_rectangle_lines_rounded_rotated_ex(
967    x: f32,
968    y: f32,
969    w: f32,
970    h: f32,
971    rotation: f32,
972    top_left: f32,
973    top_right: f32,
974    bottom_left: f32,
975    bottom_right: f32,
976    thickness: f32,
977    color: Color,
978) {
979    ctx(|s| {
980        s.draw_state.draw_rectangle_lines_rotated(
981            x,
982            y,
983            w,
984            h,
985            rotation,
986            top_left,
987            top_right,
988            bottom_left,
989            bottom_right,
990            thickness,
991            color,
992        )
993    });
994}
995
996/// Draws a filled circle centered at `(x, y)` with radius `r`.
997///
998/// # Examples
999///
1000/// ```
1001/// draw_circle(300.0, 300.0, 40.0, BLUE);
1002/// ```
1003pub fn draw_circle(x: f32, y: f32, r: f32, color: Color) {
1004    ctx(|s| s.draw_state.draw_circle(x, y, r, color));
1005}
1006
1007/// Draws the outline of a circle centered at `(x, y)` with radius `r`.
1008///
1009/// # Examples
1010///
1011/// ```
1012/// draw_circle_lines(300.0, 300.0, 40.0, 3.0, WHITE);
1013/// ```
1014
1015pub fn draw_circle_lines(x: f32, y: f32, r: f32, thickness: f32, color: Color) {
1016    ctx(|s| s.draw_state.draw_circle_lines(x, y, r, thickness, color));
1017}
1018
1019/// Draws a filled triangle from three points.
1020///
1021/// # Examples
1022///
1023/// ```
1024/// draw_triangle(100.0, 200.0, 200.0, 200.0, 150.0, 100.0, YELLOW);
1025/// ```
1026
1027pub fn draw_triangle(x1: f32, y1: f32, x2: f32, y2: f32, x3: f32, y3: f32, color: Color) {
1028    ctx(|s| s.draw_state.draw_triangle(x1, y1, x2, y2, x3, y3, color));
1029}
1030
1031/// Draws the outline of a triangle from three points.
1032///
1033/// # Examples
1034///
1035/// ```
1036/// draw_triangle_lines(100.0, 200.0, 200.0, 200.0, 150.0, 100.0, 3.0, WHITE);
1037/// ```
1038
1039pub fn draw_triangle_lines(
1040    x1: f32,
1041    y1: f32,
1042    x2: f32,
1043    y2: f32,
1044    x3: f32,
1045    y3: f32,
1046    thickness: f32,
1047    color: Color,
1048) {
1049    ctx(|s| {
1050        s.draw_state
1051            .draw_triangle_lines(x1, y1, x2, y2, x3, y3, thickness, color)
1052    });
1053}
1054
1055/// Draws a line segment from `(x1, y1)` to `(x2, y2)`.
1056///
1057/// # Examples
1058///
1059/// ```
1060/// draw_line(0.0, 0.0, 200.0, 150.0, 4.0, WHITE);
1061/// ```
1062
1063pub fn draw_line(x1: f32, y1: f32, x2: f32, y2: f32, thickness: f32, color: Color) {
1064    ctx(|s| s.draw_state.draw_line(x1, y1, x2, y2, thickness, color))
1065}
1066
1067/// Draws connected line segments through `points` with mitered joins.
1068/// If `closed` is true, the last point connects back to the first.
1069///
1070/// # Examples
1071///
1072/// ```
1073/// let pts = [Vector2::new(50.0, 50.0), Vector2::new(150.0, 80.0), Vector2::new(100.0, 160.0)];
1074/// draw_poly_line(&pts, 3.0, WHITE, true);
1075/// ```
1076
1077pub fn draw_poly_line(points: &[Vector2], thickness: f32, color: Color, closed: bool) {
1078    ctx(|s| {
1079        s.draw_state
1080            .draw_poly_line_miter(points, thickness, color, closed)
1081    })
1082}
1083
1084/// Draws connected line segments through `points` with rounded joints and caps.
1085/// If `closed` is true, the last point connects back to the first.
1086///
1087/// # Examples
1088///
1089/// ```
1090/// let pts = [Vector2::new(50.0, 50.0), Vector2::new(150.0, 80.0), Vector2::new(100.0, 160.0)];
1091/// draw_poly_line_rounded(&pts, 6.0, WHITE, false);
1092/// ```
1093
1094pub fn draw_poly_line_rounded(points: &[Vector2], thickness: f32, color: Color, closed: bool) {
1095    ctx(|s| {
1096        s.draw_state
1097            .draw_poly_line(points, thickness, color, closed, true)
1098    })
1099}
1100
1101/// Draws a filled convex polygon from `points` as a triangle fan.
1102/// Fewer than 3 points draws nothing. Use `draw_polygon_concave` for concave shapes.
1103///
1104/// # Examples
1105///
1106/// ```
1107/// let pts = [
1108///     Vector2::new(100.0, 100.0), Vector2::new(200.0, 100.0),
1109///     Vector2::new(220.0, 180.0), Vector2::new(80.0, 180.0),
1110/// ];
1111/// draw_polygon(&pts, GREEN);
1112/// ```
1113pub fn draw_polygon(points: &[Vector2], color: Color) {
1114    ctx(|s| s.draw_state.draw_polygon(points, color))
1115}
1116
1117/// Draws a filled polygon that may be concave, using ear clipping.
1118/// Self-intersecting polygons may not render correctly.
1119///
1120/// # Examples
1121///
1122/// ```
1123/// let pts = [
1124///     Vector2::new(100.0, 100.0), Vector2::new(200.0, 100.0),
1125///     Vector2::new(150.0, 150.0), Vector2::new(200.0, 200.0),
1126///     Vector2::new(100.0, 200.0),
1127/// ];
1128/// draw_polygon_concave(&pts, RED);
1129/// ```
1130pub fn draw_polygon_concave(points: &[Vector2], color: Color) {
1131    ctx(|s| s.draw_state.draw_polygon_concave(points, color))
1132}
1133
1134/// Draws text with its top-left corner at `(x, y)` with the given font, size, and color.
1135///
1136/// # Examples
1137///
1138/// ```
1139/// draw_text("Hello", 10.0, 10.0, 32.0, None, WHITE);           // default font
1140/// draw_text("Hello", 10.0, 10.0, 32.0, Some(&font), WHITE);    // loaded font
1141/// ```
1142pub fn draw_text(t: &str, x: f32, y: f32, size: f32, font: Option<&Font>, color: Color) {
1143    ctx(|s| s.draw_state.draw_text(&s.fonts, t, x, y, size, font, color));
1144}
1145
1146/// Draws a collection of `Span`s in sequence where each Span can have different properties such as
1147/// - text
1148/// - color
1149/// - size
1150/// - font
1151/// The `spans` should implement IntoIterator. Which means you can just pass an iterator.
1152///
1153/// ## Examples
1154///
1155/// ```
1156/// draw_rich_text(vec2(10.0, 10.0), &[
1157///     span("Hello there\n", WHITE),
1158///     span("My name is ", WHITE),
1159///     span("John Doe", RED)
1160///         .with_color(RED)
1161///         .with_size(32.0)
1162/// ]);
1163/// ```
1164pub fn draw_rich_text<'a, I>(
1165    position: Vector2,
1166    size: f32,
1167    font: Option<&Font>,
1168    color: Color,
1169    spans: I,
1170) where
1171    I: IntoIterator,
1172    I::Item: Borrow<Span<'a>>,
1173{
1174    ctx(|s| {
1175        s.draw_state
1176            .draw_richtext(position, size, font, color, spans)
1177    })
1178}
1179
1180/// Loads a `.ttf`/`.otf` font from path and returns the `Font` object.
1181/// (Do not load the font every frame, it will lag)
1182///
1183/// # Examples
1184///
1185/// ```
1186/// // Put this before the `flake::run()` to avoid loading it each frame
1187/// let font = load_font_from_path("src/Arial.ttf");
1188///
1189/// flake::run(|| {
1190///     draw_text("Hello", 10.0, 10.0, 32.0, Some(&font), WHITE)
1191/// })
1192/// ```
1193pub fn load_font_from_path(path: &str) -> Font {
1194    if STATE.get().is_some() {
1195        return ctx(|s| {
1196            s.load_font_from_path(path);
1197            s.fonts[s.fonts.len() - 1].clone()
1198        });
1199    }
1200
1201    PENDING_CONFIG.with_borrow_mut(|s| {
1202        let font = Font::from_path(s.fonts.len() + 1, path);
1203        s.fonts.push(font.clone());
1204        font
1205    })
1206}
1207
1208/// Loads a `.ttf`/`.otf` font from bytes and returns the `Font` object.
1209/// (Do not load the font every frame, it will lag)
1210///
1211/// # Examples
1212///
1213/// ```
1214/// // Put this before the `flake::run()` to avoid loading it each frame
1215/// let font = load_font_from_bytes(include_bytes!("Arial.ttf"));
1216///
1217/// flake::run(|| {
1218///     draw_text("Hello", 10.0, 10.0, 32.0, Some(&font), WHITE)
1219/// })
1220/// ```
1221pub fn load_font_from_bytes(bytes: &[u8]) -> Font {
1222    if STATE.get().is_some() {
1223        return ctx(|s| {
1224            s.load_font_from_bytes(bytes);
1225            s.fonts[s.fonts.len() - 1].clone()
1226        });
1227    }
1228
1229    PENDING_CONFIG.with_borrow_mut(|s| {
1230        let font = Font::from_bytes(s.fonts.len() + 1, bytes);
1231        s.fonts.push(font.clone());
1232        font
1233    })
1234}
1235
1236/// Returns the (width, height) of `text` when drawn with `draw_text` at this size.
1237pub fn measure_text(t: &str, size: f32, font: Option<&Font>) -> Vector2 {
1238    let (w, h) = ctx(|s| s.measure_text(t, size, font));
1239    Vector2::new(w, h)
1240}
1241
1242/// Draws a line from `(x1, y1)` to `(x2, y2)` with a triangular head at the end.
1243/// The tip extends `head_size` past `(x2, y2)`.
1244pub fn draw_arrow(
1245    x1: f32,
1246    y1: f32,
1247    x2: f32,
1248    y2: f32,
1249    thickness: f32,
1250    head_size: f32,
1251    color: Color,
1252) {
1253    ctx(|s| {
1254        s.draw_state
1255            .draw_arrow(x1, y1, x2, y2, thickness, head_size, color)
1256    });
1257}
1258
1259/// Returns the size of the monitor the window is on, or the window size if it can't be determined.
1260pub fn screen_size() -> Vector2 {
1261    let win = get_window();
1262    match win.current_monitor() {
1263        Some(m) => {
1264            let s = m.size();
1265            Vector2::new(s.width as f32, s.height as f32)
1266        }
1267        None => window_size(),
1268    }
1269}
1270
1271pub fn screen_width() -> f32 {
1272    screen_size().x
1273}
1274pub fn screen_height() -> f32 {
1275    screen_size().y
1276}
1277
1278// -- TEXTURES --------------------------------------------------------------------------------------------------------------
1279
1280/// Creates an empty texture of the given size. Fill it with `update_texture`.
1281pub fn create_empty_texture(width: u32, height: u32, filter_type: FilterType) -> Texture {
1282    ctx(|s| {
1283        let gpu = GpuTexture::empty(
1284            &s.device,
1285            width,
1286            height,
1287            filter_type,
1288            wgpu::TextureFormat::Rgba8UnormSrgb,
1289        )
1290        .expect("Couldn't create empty GpuTexture");
1291
1292        Texture {
1293            id: s.add_gpu_texture(gpu, false),
1294            width,
1295            height,
1296        }
1297    })
1298}
1299
1300/// Loads a texture from an image file using linear filtering. Panics if the file can't be read or decoded.
1301pub fn load_texture(path: &str) -> Texture {
1302    ctx(|s| {
1303        let image = image::load_from_memory(&std::fs::read(path).unwrap()).unwrap();
1304        let width = image.width();
1305        let height = image.height();
1306
1307        Texture {
1308            id: s.add_texture(image, FilterType::Linear),
1309            width,
1310            height,
1311        }
1312    })
1313}
1314
1315/// Same as `load_texture`, with an explicit `FilterType` (e.g. nearest for pixel art).
1316pub fn load_texture_with_filter_type(path: &str, filter_type: FilterType) -> Texture {
1317    ctx(|s| {
1318        let image = image::load_from_memory(&std::fs::read(path).unwrap()).unwrap();
1319        let width = image.width();
1320        let height = image.height();
1321
1322        Texture {
1323            id: s.add_texture(image, filter_type),
1324            width,
1325            height,
1326        }
1327    })
1328}
1329
1330/// Loads a texture from encoded image bytes (e.g. `include_bytes!`) using linear filtering.
1331pub fn load_texture_from_bytes(bytes: &[u8]) -> Texture {
1332    ctx(|s| {
1333        let image = image::load_from_memory(bytes).unwrap();
1334        let (width, height) = image.dimensions();
1335
1336        Texture {
1337            id: s.add_texture(image, FilterType::Linear),
1338            width,
1339            height,
1340        }
1341    })
1342}
1343
1344/// Loads a texture from raw RGBA `f32` pixels. `data.len()` must equal `width * height * 4`, otherwise this panics.
1345pub fn load_texture_from_bytes_with_filter_type(bytes: &[u8], filter_type: FilterType) -> Texture {
1346    ctx(|s| {
1347        let image = image::load_from_memory(bytes).unwrap();
1348        let (width, height) = image.dimensions();
1349
1350        Texture {
1351            id: s.add_texture(image, filter_type),
1352            width,
1353            height,
1354        }
1355    })
1356}
1357
1358/// Loads a texture from raw RGBA `f32` pixels. `data.len()` must equal `width * height * 4`, otherwise this panics.
1359pub fn load_texture_from_data(width: u32, height: u32, data: &[f32]) -> Texture {
1360    ctx(|s| {
1361        let img_buf = ImageBuffer::<Rgba<f32>, Vec<f32>>::from_raw(width, height, data.to_vec())
1362            .expect("Buffer size mismatch");
1363
1364        let dynamic_img = DynamicImage::ImageRgba32F(img_buf);
1365
1366        Texture {
1367            id: s.add_texture(dynamic_img, FilterType::Linear),
1368            width,
1369            height,
1370        }
1371    })
1372}
1373
1374/// Loads a texture from raw RGBA `f32` pixels.
1375/// `data.len()` must equal `width * height * 4`, otherwise this panics.
1376/// (Use nearest for pixel art)
1377pub fn load_texture_from_data_with_filter_type(
1378    width: u32,
1379    height: u32,
1380    data: &[f32],
1381    filter_type: FilterType,
1382) -> Texture {
1383    ctx(|s| {
1384        let img_buf = ImageBuffer::<Rgba<f32>, Vec<f32>>::from_raw(width, height, data.to_vec())
1385            .expect("Buffer size mismatch");
1386
1387        let dynamic_img = DynamicImage::ImageRgba32F(img_buf);
1388
1389        Texture {
1390            id: s.add_texture(dynamic_img, filter_type),
1391            width,
1392            height,
1393        }
1394    })
1395}
1396
1397/// Creates a texture from an `Image`.
1398pub fn load_texture_from_image(image: &Image) -> Texture {
1399    let tex = create_empty_texture(image.width, image.height, image.filter_type);
1400    update_texture(tex, image);
1401
1402    tex
1403}
1404
1405/// Draws a texture stretched to `w` x `h` with its top-left at `(x, y)`.
1406/// `tint` multiplies the texture color (use `WHITE` for none).
1407pub fn draw_texture(texture: Texture, x: f32, y: f32, w: f32, h: f32, tint: Color) {
1408    ctx(|s| s.draw_state.draw_texture(texture, x, y, w, h, tint))
1409}
1410
1411/// Draws a texture with extra options from `DrawTextureParams`: destination size,
1412/// source rect, horizontal/vertical flip, rotation (radians), pivot, and tint.
1413pub fn draw_texture_ex(texture: Texture, x: f32, y: f32, p: DrawTextureParams) {
1414    ctx(|s| s.draw_state.draw_texture_ex(texture, x, y, p))
1415}
1416
1417/// Replaces the pixels of an existing texture with those from `image`.
1418pub fn update_texture(texture: Texture, image: &Image) {
1419    ctx(|s| s.update_texture(texture.id, image))
1420}
1421
1422/// Creates a new RenderTarget.
1423pub fn render_target(width: u32, height: u32, filter_type: FilterType) -> RenderTarget {
1424    ctx(|s| s.create_render_target(width, height, filter_type))
1425}
1426
1427/// Sets the currently active camera being used to draw on.
1428pub fn set_camera(cam: &Camera2D) {
1429    ctx(|s| s.set_camera(cam))
1430}
1431
1432/// Resets the camera to the default screen one.
1433pub fn set_default_camera() {
1434    ctx(|s| s.set_default_camera())
1435}