1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
use super::obj::*; use super::sprite::{gui__col_tex_ps, gui__pos_col_tex_vs, sampler}; use crate::uses::{math::*, *}; use crate::GL::{shader::*, tex::*, window::*, VTex2d, VaoBinding}; pub struct Sprite9<'a, S> { pub pos: Vec2, pub size: Vec2, pub corner: f32, pub color: Color, pub tex: &'a VTex2d<S, u8>, } impl<'a, S: TexSize> Sprite9<'a, S> { #[inline(always)] pub fn compare(&self, crop: &Crop, r: &Sprite9Impl<S>) -> State { let &Self { pos, size, corner, color, tex } = self; let xyzw = (State::XYZW | State::UV).or_def(geom_cmp(pos, size, crop, &r.base) || corner != r.corner); let rgba = State::RGBA.or_def(color != r.base.color); let _tex = State::UV.or_def(!ptr::eq(tex, r.tex)); let ord = State::MISMATCH.or_def((!_tex.is_empty() && atlas_cmp(tex, r.tex)) || (!rgba.is_empty() && ordering_cmp::<S, _>(color, r))); ord | xyzw | rgba | _tex } pub fn obj(self, crop: Crop) -> Sprite9Impl<S> { let Self { pos, size, corner, color, tex } = self; Sprite9Impl { base: Base { pos, size, crop, color }, corner, tex, } } } pub struct Sprite9Impl<S> { base: Base, corner: f32, tex: *const VTex2d<S, u8>, } impl<S: TexSize> Sprite9Impl<S> { pub fn batchable(&self, r: &Self) -> bool { self.ordered() == r.ordered() && atlas_cmp(self.tex, r.tex) } } impl<S: TexSize> Object for Sprite9Impl<S> { fn base(&self) -> &Base { &self.base } fn write_mesh(&self, range: BatchRange) { let (crop, &Base { pos, size, color, .. }, (u1, v1, u2, v2)) = (self.base.bound_box(), self.base(), unsafe { &*self.tex }.region); let c = size.x().min(size.y()) * self.corner.min(0.5).max(0.); write_sprite9((Window::aspect(), pos, size, (c, c), crop, (u1, v2, u2, v1), color), range); } fn batch_draw(&self, b: &VaoBinding<u16>, (offset, num): (u16, u16)) { let s = UnsafeOnce!(Shader, { EXPECT!(Shader::new((gui__pos_col_tex_vs, gui__col_tex_ps))) }); let t = unsafe { &*self.tex }.tex.Bind(sampler()); let _ = Uniforms!(s, ("src", &t)); b.Draw((num, offset, gl::TRIANGLES)); } fn vert_count(&self) -> u32 { 16 } fn ordered(&self) -> bool { S::TYPE == gl::RGBA || Object::ordered(self) } fn gen_idxs(&self, (start, size): (u16, u16)) -> Vec<u16> { sprite9_idxs((start, size)) } } type Sprite9Desc = (Vec2, Vec2, Vec2, Vec2, Crop, TexCoord, Color); pub fn write_sprite9((aspect, pos, size, corner, (crop1, crop2), (u1, v1, u2, v2), color): Sprite9Desc, (z, state, xyzw, rgba, uv): BatchRange) { if state.contains(State::XYZW) { let (((x1, y1), (x2, y2), (m1x, m1y), (m2x, m2y)), (u1, v1, u2, v2), (m1u, m1v, m2u, m2v)) = <(vec4<vec2<f16>>, vec4<f16>, vec4<f16>)>::to({ let (xy1, xy2) = (pos, pos.sum(size)); let (m1, m2, ms) = (xy1.sum(corner), xy2.sub(corner), corner); let (uv, muv) = { let wh = (u2 - u1, v2 - v1).div(ms); let (u1m, v1m) = (u1, v1).sum(wh.mul(m1.sub(crop2)).mul(crop2.ls(m1))); let (u2m, v2m) = (u1, v1).sum(wh.mul(crop1.sub(m2)).mul(crop1.gt(m2))); let (u1, v1) = (u2, v2).sub(wh.mul(crop1.sub(xy1))); let (u2, v2) = (u2, v2).sub(wh.mul(xy2.sub(crop2))); ((u1, v2, u2, v1), (u1m, v2m, u2m, v1m)) }; ( (crop1.mul(aspect), crop2.mul(aspect), m1.clmp(crop1, crop2).mul(aspect), m2.clmp(crop1, crop2).mul(aspect)), uv, muv, ) }); const O: f16 = f16::ZERO; if state.contains(State::XYZW) { #[rustfmt::skip] xyzw[..64].copy_from_slice(&[x1, y1, z, O, m1x, y1, z, O, m2x, y1, z, O, x2, y1, z, O, x1, m1y, z, O, m1x, m1y, z, O, m2x, m1y, z, O, x2, m1y, z, O, x1, m2y, z, O, m1x, m2y, z, O, m2x, m2y, z, O, x2, m2y, z, O, x1, y2, z, O, m1x, y2, z, O, m2x, y2, z, O, x2, y2, z, O]); } if state.contains(State::UV) { #[rustfmt::skip] uv[..32].copy_from_slice(&[u1, v2, m1u, v2, m2u, v2, u2, v2, u1, m2v, m1u, m2v, m2u, m2v, u2, m2v, u1, m1v, m1u, m1v, m2u, m1v, u2, m1v, u1, v1, m1u, v1, m2u, v1, u2, v1]); } } if state.contains(State::RGBA) { let (r, g, b, a) = vec4::to(color.mul(255).clmp(0, 255).round()); #[rustfmt::skip] rgba[..64].copy_from_slice(&[r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a]); } } pub fn sprite9_idxs((start, size): (u16, u16)) -> Vec<u16> { let mut v = vec![]; v.reserve(usize::to(size) * 8 / 27); for i in (start..(start + size)).step_by(16) { let s = |j| i + j; #[rustfmt::skip] v.extend_from_slice(&[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), 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), 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)]); } v }