Skip to main content

grafix_toolbox/gui/primitive/
sprite9.rs

1use super::*;
2
3pub struct Sprite9<'r, S> {
4	pub pos: Vec2,
5	pub size: Vec2,
6	pub corner: f32,
7	pub color: Color,
8	pub tex: &'r VTex2d<S, u8>,
9}
10impl<S: TexSize> Sprite9<'_, S> {
11	pub fn compare(&self, crop: &Geom, r: &Sprite9Impl<S>) -> State {
12		let Self { pos, size, corner, color, tex: tex_new } = *self;
13		let xyzw = (State::XYZW | State::UV).or_def(geom_cmp(pos, size, crop, &r.base) || corner != r.corner);
14		let rgba = State::RGBA.or_def(color != r.base.color);
15		let ord = State::MISMATCH.or_def(!ptr::eq(r.tex, tex_new) || (!rgba.is_empty() && ordering_cmp::<S, _>(color, r)));
16		ord | xyzw | rgba
17	}
18	pub fn obj(self, crop: Geom) -> Sprite9Impl<S> {
19		let Self { pos, size, corner, color, tex } = self;
20		Sprite9Impl { base: Base { pos, size, crop, color }, corner, tex }
21	}
22}
23pub struct Sprite9Impl<S> {
24	base: Base,
25	corner: f32,
26	tex: *const VTex2d<S, u8>,
27}
28impl<S: TexSize> Sprite9Impl<S> {
29	pub fn batchable(&self, r: &Self) -> bool {
30		self.ordered() == r.ordered() && atlas_cmp(self.tex, r.tex)
31	}
32}
33impl<S: TexSize> Primitive for Sprite9Impl<S> {
34	fn base(&self) -> &Base {
35		&self.base
36	}
37	fn write_mesh(&self, aspect: Vec2, range: BatchedObj) {
38		let (crop, &Base { pos, size, color, .. }, (u1, v1, u2, v2)) = (self.base.bound_box(), self.base(), unsafe { &*self.tex }.region);
39		let c = size.min_comp() * self.corner.clamp(0., 0.5);
40		write_sprite9((aspect, pos, size, (c, c), crop, (u1, v2, u2, v1), color), range);
41	}
42	fn batch_draw(&self, b: &VaoBind<u16>, (offset, num): (u16, u16)) {
43		let s = LeakyStatic!(Shader, { [vs_gui__pos_col_tex, ps_gui__col_tex].pipe(Shader::pure) });
44
45		let t = unsafe { &*self.tex }.atlas.Bind(sampler());
46		let _ = Uniforms!(s, ("src", t));
47		b.Draw((num, offset, gl::TRIANGLES));
48	}
49
50	fn vert_count(&self) -> u32 {
51		16
52	}
53	fn ordered(&self) -> bool {
54		S::TYPE == gl::RGBA || Primitive::ordered(self)
55	}
56	fn gen_idxs(&self, (start, size): (u16, u16)) -> Box<[u16]> {
57		sprite9_idxs((start, size))
58	}
59}
60
61type Sprite9Desc = (Vec2, Vec2, Vec2, Vec2, Geom, TexCoord, Color);
62pub fn write_sprite9((aspect, pos, size, corner, _crop @ (p1, p2), (u1, v1, u2, v2), color): Sprite9Desc, BatchedObj { z, state, xyzw, rgba, uv }: BatchedObj) {
63	if state.contains(State::XYZW) {
64		let (((x1, y1), (x2, y2), (m1x, m1y), (m2x, m2y)), (u1, v1, u2, v2), (m1u, m1v, m2u, m2v)) = <_>::to({
65			let (xy1, xy2) = (pos, pos.sum(size));
66			let (m1, m2, ms) = (xy1.sum(corner), xy2.sub(corner), corner);
67			let (uv, muv) = {
68				let wh = (u2 - u1, v2 - v1).div(ms);
69				let (u1m, v1m) = (u1, v1).sum(wh.mul(m1.sub(p2)).mul(p2.ls(m1)));
70				let (u2m, v2m) = (u1, v1).sum(wh.mul(p1.sub(m2)).mul(p1.gt(m2)));
71				let (u1, v1) = (u2, v2).sub(wh.mul(p1.sub(xy1)));
72				let (u2, v2) = (u2, v2).sub(wh.mul(xy2.sub(p2)));
73				((u1, v2, u2, v1), (u1m, v2m, u2m, v1m))
74			};
75			((p1.mul(aspect), p2.mul(aspect), m1.clmp(p1, p2).mul(aspect), m2.clmp(p1, p2).mul(aspect)), uv, muv)
76		});
77		let O = f16::ZERO;
78
79		if state.contains(State::XYZW) {
80			#[rustfmt::skip]
81			xyzw[..64].copy_from_slice(&[x1, y1,  z, O,  m1x, y1,  z, O,  m2x, y1,  z, O,  x2, y1,  z, O,
82										 x1, m1y, z, O,  m1x, m1y, z, O,  m2x, m1y, z, O,  x2, m1y, z, O,
83										 x1, m2y, z, O,  m1x, m2y, z, O,  m2x, m2y, z, O,  x2, m2y, z, O,
84										 x1, y2,  z, O,  m1x, y2,  z, O,  m2x, y2,  z, O,  x2, y2,  z, O]);
85		}
86
87		if state.contains(State::UV) {
88			#[rustfmt::skip]
89			uv[..32].copy_from_slice(&[u1, v2,   m1u, v2,   m2u, v2,   u2, v2,
90									   u1, m2v,  m1u, m2v,  m2u, m2v,  u2, m2v,
91									   u1, m1v,  m1u, m1v,  m2u, m1v,  u2, m1v,
92									   u1, v1,   m1u, v1,   m2u, v1,   u2, v1]);
93		}
94	}
95
96	if state.contains(State::RGBA) {
97		let (r, g, b, a) = vec4(color.mul(255).clmp(0, 255).round());
98		#[rustfmt::skip]
99		rgba[..64].copy_from_slice(&[r, g, b, a,  r, g, b, a,  r, g, b, a,  r, g, b, a,
100									 r, g, b, a,  r, g, b, a,  r, g, b, a,  r, g, b, a,
101									 r, g, b, a,  r, g, b, a,  r, g, b, a,  r, g, b, a,
102									 r, g, b, a,  r, g, b, a,  r, g, b, a,  r, g, b, a]);
103	}
104}
105
106pub fn sprite9_idxs((start, size): (u16, u16)) -> Box<[u16]> {
107	(start..(start + size))
108		.step_by(16)
109		.flat_map(|i| {
110			let s = |j| i + j;
111			#[rustfmt::skip] let s =
112			[s(0), s(1), s(4), s(4), s(1), s(5),     s(5), s(1), s(2), s(2), s(5), s(6),       s(6), s(2), s(3), s(3), s(6), s(7),
113			 s(7), s(6), s(11), s(11), s(6), s(10),  s(10), s(6), s(5), s(5), s(10), s(9),     s(9), s(5), s(4), s(4), s(9), s(8),
114			 s(8), s(9), s(12), s(12), s(9), s(13),  s(13), s(9), s(10), s(10), s(13), s(14),  s(14), s(10), s(11), s(11), s(14), s(15)];
115			s
116		})
117		.collect()
118}