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}