1use super::*;
2
3DRAWABLE!(Rect, Rect);
4DRAWABLE!(Sprite<'r, RGB>, ImgRGB);
5DRAWABLE!(Sprite<'r, RGBA>, ImgRGBA);
6DRAWABLE!(Sprite9<'r, RGB>, Img9RGB);
7DRAWABLE!(Sprite9<'r, RGBA>, Img9RGBA);
8DRAWABLE!(Frame9<'r>, Frame9);
9DRAWABLE!(Text<'r, '_>, Text);
10
11pub struct RenderLock<'l> {
12 pub(super) r: Renderer,
13 n: u32,
14 crop: Rc<Cell<Geom>>,
15 logics: Vec<LogicStorage<'l>>,
16}
17impl<'l> RenderLock<'l> {
18 pub fn theme(&self) -> &'l Theme {
19 unsafe { mem::transmute(&self.r.theme) }
20 }
21 pub fn clip(&self, s: Surf) -> ClipLock {
22 let Self { crop, .. } = self;
23 let (lock, prev_crop @ (c1, c2)) = (crop.clone(), crop.get());
24 let (p1, p2) = s.b_box();
25 crop.set((p1.fmax(c1), p2.fmin(c2)));
26 ClipLock { lock, prev_crop }
27 }
28 pub fn unclipped(&mut self, f: impl FnOnce(&mut Self)) {
29 let c = self.crop.replace(uncropped());
30 f(self);
31 self.crop.set(c)
32 }
33 pub fn draw<'r: 'l>(&mut self, prim: impl DrawablePrimitive<'r>) {
34 let Self { ref mut r, ref mut n, ref crop, .. } = *self;
35 prim.draw(*n, (&**crop).bind(), r);
36 *n += 1;
37 }
38 pub fn draw_with_logic<'r: 'l>(&mut self, prim: impl DrawablePrimitive<'r>, func: impl 'l + EventReaction, id: LogicId) {
39 let Self { ref mut r, ref mut n, ref crop, ref mut logics } = *self;
40 prim.draw(*n, (&**crop).bind(), r);
41 let (id, bound, func) = (id, LogicBound::Obj(*n), Box(func));
42 logics.push(LogicStorage { id, bound, func });
43 *n += 1;
44 }
45 pub fn logic(&mut self, s: Surf, func: impl 'l + EventReaction, id: LogicId) {
46 let (id, bound, func) = (id, LogicBound::Crop(s.b_box()), Box(func));
47 self.logics.push(LogicStorage { id, bound, func });
48 }
49 pub fn hovers_in(&self, s: Surf) -> bool {
50 inside(s.b_box(), self.r.mouse_pos)
51 }
52 pub fn hovered(&self) -> bool {
53 let Self { ref r, n, .. } = *self;
54 if n < 1 {
55 return false;
56 }
57 inside(r.cache.b_box(n - 1), r.mouse_pos)
58 }
59 pub fn focused(&self, l: LogicId) -> bool {
60 l == self.r.focus
61 }
62 pub fn mouse_pos(&self) -> Vec2 {
63 self.r.mouse_pos
64 }
65 pub fn aspect(&self) -> Vec2 {
66 self.r.aspect
67 }
68 pub fn unlock(self, w: &mut impl Frame, events: &mut Vec<Event>) -> Renderer {
69 let Self { mut r, logics, n, .. } = self;
70 if n < u32(r.cache.objs.len()) {
71 r.cache.shrink(n);
72 r.flush |= State::BATCH_RESIZED;
73 }
74 r.consume_events(logics, events);
75 r.render(w);
76 r
77 }
78 pub fn unlock_skip_render(self, _: &mut impl Frame, events: &mut Vec<Event>) -> Renderer {
79 let Self { mut r, logics, n, .. } = self;
80 if n < u32(r.cache.objs.len()) {
81 r.cache.shrink(n);
82 r.flush |= State::BATCH_RESIZED;
83 }
84 r.consume_events(logics, events);
85 r
86 }
87}
88
89#[derive(Default)]
90pub struct Renderer {
91 vao: Vao<u16>,
92 idxs: IdxArrStorage,
93 xyzw: ArrStorage<f16>,
94 uv: ArrStorage<f16>,
95 rgba: ArrStorage<u8>,
96 cache: RenderCache,
97 flush: State,
98 status: State,
99 aspect: Vec2,
100 focus: LogicId,
101 mouse_pos: Vec2,
102 theme: Theme,
103 pub(super) storage: Cell<ElementStorage>,
104}
105impl Renderer {
106 pub fn new(theme: Theme, f: &impl Frame) -> Self {
107 Self { theme, aspect: f.clip_aspect(), ..Def() }
108 }
109 pub fn lock<'a>(self) -> RenderLock<'a> {
110 RenderLock {
111 r: self,
112 crop: uncropped().pipe(Cell).pipe(Rc::new),
113 n: 0,
114 logics: vec![],
115 }
116 }
117 fn consume_events(&mut self, mut logics: Vec<LogicStorage>, events: &mut Vec<Event>) {
118 let Self { ref cache, ref mut focus, ref mut mouse_pos, .. } = *self;
119 let b_box = |l: &mut LogicStorage| {
120 use LogicBound::*;
121 match l.bound {
122 Crop(b_box) => b_box,
123 Obj(at) => cache.b_box(at).tap(|b| l.bound = Crop(*b)),
124 }
125 };
126
127 events.retain(|e| {
128 map_variant!(&MouseMove { at, .. } = e => *mouse_pos = at);
129 let (refocus, mouse) = (matches!(e, MouseButton { m, .. } if m.contains(Mod::PRESS)), *mouse_pos);
130
131 if *focus != 0 {
132 let focused = logics.iter_mut().rev().find(|l| *focus == l.id);
133 if let Some(l) = focused {
134 if !refocus || inside(b_box(l), mouse) {
135 match (l.func)(e, true, mouse) {
136 Reject => return true,
137 Accept => return false,
138 DropFocus => {
139 *focus = 0;
140 return false;
141 }
142 Pass => (),
143 }
144 } else {
145 (l.func)(&Defocus, true, mouse);
146 *focus = 0;
147 }
148 } else {
149 *focus = 0;
150 }
151 }
152
153 for (b, l) in logics.iter_mut().rev().map(|l| (b_box(l), l)) {
154 if !inside(b, mouse) {
155 continue;
156 }
157
158 if refocus
159 && *focus == 0 && let Accept = (l.func)(&OfferFocus, false, mouse)
160 {
161 *focus = l.id;
162 }
163
164 match (l.func)(e, *focus == l.id, mouse) {
165 Reject => return true,
166 Accept | DropFocus => return false,
167 Pass => (),
168 }
169 }
170 true
171 });
172 }
173 fn render(&mut self, frame: &mut impl Frame) {
174 let Self { vao, idxs, xyzw, uv, rgba, cache, flush, status, aspect, .. } = self;
175
176 if !flush.is_empty() {
177 let flush = cache.flush(frame.clip_aspect(), &mut idxs.buff, &mut xyzw.buff, &mut rgba.buff, &mut uv.buff);
178
179 idxs.flush(flush.0, |o| vao.BindIdxs(o));
180 xyzw.flush(flush.1, |o| vao.AttribFmt(o, (0, 4)));
181 rgba.flush(flush.2, |o| vao.AttribFmt(o, (1, 4, true)));
182 uv.flush(flush.3, |o| vao.AttribFmt(o, (2, 2)));
183 }
184
185 frame.bind();
186 frame.ClearDepth(1);
187
188 GL::BlendFunc::Save();
189 GL::DepthFunc::Save();
190 GLSave!(CULL_FACE, DEPTH_TEST, DEPTH_WRITABLE, BLEND);
191
192 GLDisable!(CULL_FACE);
193 GLEnable!(DEPTH_TEST, DEPTH_WRITABLE);
194 GL::BlendFunc::Set((gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA));
195 GL::DepthFunc::Set(gl::LEQUAL);
196
197 {
198 let v = vao.Bind();
199 GLDisable!(BLEND);
200 cache.draw_opaque_batches(&v);
201
202 GLEnable!(BLEND);
203 cache.draw_translucent_batches(&v);
204 }
205
206 GLRestore!(CULL_FACE, DEPTH_TEST, DEPTH_WRITABLE, BLEND);
207 GL::BlendFunc::Restore();
208 GL::DepthFunc::Restore();
209
210 (*status, *flush, *aspect) = (State::XYZW.or_def(frame.clip_aspect() != *aspect), State::empty(), frame.clip_aspect());
211 }
212}
213
214#[derive(Default)]
215struct Storage<T: spec::Buffer, D> {
216 obj: spec::ArrObj<T, D>,
217 buff: Vec<D>,
218 size: usize,
219}
220impl<T: spec::Buffer, D: Copy> Storage<T, D> {
221 fn flush(&mut self, from: Option<usize>, mut rebind: impl FnMut(&spec::ArrObj<T, D>)) {
222 let Some(from) = from else { return };
223
224 let Self { ref mut obj, ref buff, ref mut size } = *self;
225 let new_size = buff.len();
226 if new_size <= *size && new_size * 2 > *size {
227 obj.MapMut((from..new_size, gl::MAP_INVALIDATE_RANGE_BIT)).mem().copy_from_slice(&buff[from..]);
228 return;
229 }
230
231 (*obj, *size) = ((buff, gl::DYNAMIC_STORAGE_BIT | gl::MAP_WRITE_BIT).pipe(spec::ArrObj::new), new_size);
232 rebind(obj);
233 }
234}
235type IdxArrStorage = Storage<spec::Index, u16>;
236type ArrStorage<T> = Storage<spec::Attribute, T>;
237
238pub struct ClipLock {
239 prev_crop: Geom,
240 lock: Rc<Cell<Geom>>,
241}
242impl Drop for ClipLock {
243 fn drop(&mut self) {
244 self.lock.set(self.prev_crop);
245 }
246}
247
248fn inside(g: Geom, p: Vec2) -> bool {
249 contains(g, (p, p))
250}
251
252fn uncropped() -> Geom {
253 let L = f32::INFINITY;
254 ((-L, -L), (L, L))
255}