Skip to main content

grafix_toolbox/gui/
render.rs

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}