1use crate::graphics::Canvas;
7use crate::graphics::*;
8use pix::chan::Channel;
9use pix::el::Pixel;
10use std::{
11 future::Future,
12 pin::Pin,
13 sync::{
14 atomic::{AtomicU32, Ordering},
15 Arc, Condvar, Mutex,
16 },
17 task::{Context, Poll},
18};
19
20static BACKGROUND_RED: AtomicU32 = AtomicU32::new(0);
21static BACKGROUND_GREEN: AtomicU32 = AtomicU32::new(0);
22static BACKGROUND_BLUE: AtomicU32 = AtomicU32::new(0);
23
24struct FrameFuture;
25
26pub use window::input::input;
27
28impl Future for FrameFuture {
29 type Output = (std::time::Duration, f32, bool);
30
31 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
32 let internal = Internal::new_lazy();
33 let mut lock = internal.frame.lock().unwrap();
34 if let Some(secs) = lock.frame.take() {
35 Poll::Ready(secs)
36 } else {
37 lock.waker = Some(cx.waker().clone());
38 Poll::Pending
39 }
40 }
41}
42
43pub struct Frame {
45 pair: Arc<(Mutex<bool>, Condvar)>,
47 elapsed: std::time::Duration,
49 aspect: f32,
51 resized: bool,
53}
54
55impl Frame {
56 #[allow(clippy::useless_let_if_seq)] pub async fn new<P: pix::el::Pixel>(color: P) -> Frame
59 where
60 pix::chan::Ch32: From<<P as pix::el::Pixel>::Chan>,
61 {
62 let color: pix::rgb::SRgb32 = color.convert();
63 let red = color.one().to_f32();
64 let green = color.two().to_f32();
65 let blue = color.three().to_f32();
66 let red_u32 = u32::from_ne_bytes(red.to_ne_bytes());
67 let green_u32 = u32::from_ne_bytes(green.to_ne_bytes());
68 let blue_u32 = u32::from_ne_bytes(blue.to_ne_bytes());
69
70 let mut bg_changed = false;
71 if BACKGROUND_RED.load(Ordering::Relaxed) != red_u32 {
72 BACKGROUND_RED.store(red_u32, Ordering::Relaxed);
73 bg_changed = true;
74 }
75 if BACKGROUND_GREEN.load(Ordering::Relaxed) != blue_u32 {
76 BACKGROUND_GREEN.store(green_u32, Ordering::Relaxed);
77 bg_changed = true;
78 }
79 if BACKGROUND_BLUE.load(Ordering::Relaxed) != green_u32 {
80 BACKGROUND_BLUE.store(blue_u32, Ordering::Relaxed);
81 bg_changed = true;
82 }
83 let secs = FrameFuture.await;
84 let internal = Internal::new_lazy();
85 let mut cmds = internal.cmds.lock().unwrap();
86 let pair = internal.pair.clone();
87 if bg_changed {
88 cmds.push(GpuCmd::Background(red, green, blue));
89 }
90 Frame {
91 pair,
92 elapsed: secs.0,
93 aspect: secs.1,
94 resized: secs.2,
95 }
96 }
97}
98
99impl Canvas for Frame {
100 fn draw(&mut self, shader: &Shader, group: &Group) {
101 let internal = Internal::new_lazy();
102 let mut cmds = internal.cmds.lock().unwrap();
103 cmds.push(GpuCmd::Draw(shader.0, group.0));
104 }
105
106 fn set_camera(&mut self, camera: Transform) {
107 let internal = Internal::new_lazy();
108 let mut cmds = internal.cmds.lock().unwrap();
109 cmds.push(GpuCmd::SetCamera(camera));
110 }
111
112 fn set_tint<P: pix::el::Pixel>(&mut self, shader: &Shader, tint: P)
113 where
114 pix::chan::Ch32: From<<P as pix::el::Pixel>::Chan>,
115 {
116 let internal = Internal::new_lazy();
117 let mut cmds = internal.cmds.lock().unwrap();
118 let color: pix::rgb::SRgba32 = tint.convert();
119 let red = color.one().to_f32();
120 let green = color.two().to_f32();
121 let blue = color.three().to_f32();
122 let alpha = color.four().to_f32();
123 cmds.push(GpuCmd::SetTint(shader.0, [red, green, blue, alpha]));
124 }
125
126 fn draw_graphic(
127 &mut self,
128 shader: &Shader,
129 group: &Group,
130 graphic: &Texture,
131 ) {
132 let internal = Internal::new_lazy();
133 let mut cmds = internal.cmds.lock().unwrap();
134 cmds.push(GpuCmd::DrawGraphic(shader.0, group.0, graphic.0));
135 }
136
137 fn elapsed(&self) -> std::time::Duration {
138 self.elapsed
139 }
140
141 fn height(&self) -> f32 {
142 self.aspect
143 }
144
145 fn resized(&self) -> bool {
146 self.resized
147 }
148}
149
150impl Drop for Frame {
151 fn drop(&mut self) {
152 let (lock, cvar) = &*self.pair;
153 let mut started = lock.lock().unwrap();
154 *started = true;
155 cvar.notify_one();
157 }
158}