grafix-toolbox 0.8.33

Personal collection of opengl and rust tools, also serving as an functional gui crate. See ./gui/elements for premade gui elements
Documentation
use super::*;

struct Obj {
	idx: u32,
	size: u32,
}
#[derive(Default)]
pub struct Batch {
	pub idx_range: usVec2,
	pub xyzw: Vec<f16>,
	pub uv: Vec<f16>,
	pub rgba: Vec<u8>,
	objs: Vec<Obj>,
}
impl Batch {
	pub fn new(z: u32) -> Self {
		Self { objs: vec![Obj { idx: z, size: 0 }], ..Def() }
	}
	pub fn typ<'a>(&self, cache: &'a [PrimCache]) -> &'a PrimImpl {
		get(cache, self.objs.first().valid())
	}
	pub fn contains(&self, cache: &[PrimCache], (o, z): (&PrimImpl, u32)) -> bool {
		let (t, objs) = (self.typ(cache), &self.objs);
		t.batchable(o) && objs.binary_search_by(|o| o.idx.cmp(&z)).is_ok()
	}
	pub fn covers(&self, cache: &[PrimCache], (o, z): (&PrimImpl, u32)) -> bool {
		let (t, objs, obj) = (self.typ(cache), self.objs.iter(), o.obj());

		!(t.batchable(o)
			|| !t.obj().ordered()
			|| !objs.take_while(|i| i.idx <= z).any(|i| {
				let l = get(cache, i).obj().base();
				l.intersects(obj.base())
			}))
	}
	pub fn covered(&self, cache: &[PrimCache], (o, z): (&PrimImpl, u32)) -> bool {
		let (t, objs, obj) = (self.typ(cache), self.objs.iter(), o.obj());
		!(t.batchable(o)
			|| !t.obj().ordered()
			|| !objs.rev().take_while(|i| i.idx >= z).any(|i| {
				let l = get(cache, i).obj().base();
				l.intersects(obj.base())
			}))
	}
	pub fn shrink_and_empty(&mut self, cache: &mut [PrimCache], z: u32) -> bool {
		let objs = &mut self.objs;
		let l = objs.iter().rposition(|i| i.idx < z).map(|i| i + 1).unwrap_or(0);
		if !objs[l..].is_empty() {
			objs.drain(l..).for_each(|o| cache.at_mut(o.idx).state = State::MISMATCH);
			objs.first().map(|o| cache.at_mut(o.idx).state |= State::BATCH_RESIZED);
		}
		objs.is_empty()
	}
	pub fn try_add(&mut self, cache: &[PrimCache], (o, z): (&PrimImpl, u32)) -> bool {
		if !self.typ(cache).batchable(o) {
			return false;
		}

		self.objs.push(Obj { idx: z, size: 0 });
		true
	}
	pub fn interferes(&self, cache: &[PrimCache], o: &PrimImpl) -> bool {
		let (t, mut objs, obj) = (self.typ(cache).obj(), self.objs.iter(), o.obj());
		t.ordered()
			&& obj.ordered()
			&& objs.any(|i| {
				let l = get(cache, i).obj().base();
				l.intersects(obj.base())
			})
	}
	pub fn redraw(&mut self, aspect: Vec2, cache: &[PrimCache]) -> (u32, State) {
		let Self { xyzw, rgba, uv, objs, .. } = self;

		let (len, mut state) = objs.iter_mut().fold((0, State::empty()), |(start, flush), obj @ &mut Obj { idx, size }| {
			let &PrimCache { state, ref o } = cache.at(idx);
			let o = o.obj();

			let (new_size, state) = (|| {
				if (state ^ State::BATCH_RESIZED).is_empty() {
					return (size, state);
				}

				let new_size = o.vert_count();

				let state = (|| {
					if state.contains(State::MISMATCH) {
						let to = usize(start + new_size);
						xyzw.resize(to * 4, f16(0));
						rgba.resize(to * 4, 0);
						uv.resize(to * 2, f16(0));
						return State::MISMATCH;
					}

					if new_size > size {
						let O = f16::ZERO;
						let (at, s) = ulVec2((start, new_size - size));
						xyzw.splice(at * 4..at * 4, vec![O; s * 4]);
						rgba.splice(at * 4..at * 4, vec![0; s * 4]);
						uv.splice(at * 2..at * 2, vec![O; s * 2]);
						return State::FULL | State::BATCH_RESIZED;
					}

					if new_size < size {
						let (from, to) = ulVec2((start + new_size, start + size));
						xyzw.drain(from * 4..to * 4);
						rgba.drain(from * 4..to * 4);
						uv.drain(from * 2..to * 2);
						return State::FULL | State::BATCH_RESIZED;
					}

					state
				})();

				let (z, s) = <(f32, usize)>::to((idx, start));
				o.write_mesh(
					aspect,
					BatchedObj {
						z: f16(1. - z / 1000.),
						state,
						xyzw: &mut xyzw[s * 4..],
						rgba: &mut rgba[s * 4..],
						uv: &mut uv[s * 2..],
					},
				);

				(new_size, state)
			})();

			obj.size = new_size;

			(start + new_size, flush | state)
		});

		if state.contains(State::BATCH_RESIZED) {
			let to = usize(len);
			xyzw.truncate(to * 4);
			rgba.truncate(to * 4);
			uv.truncate(to * 2);
			state |= State::FULL;
		}
		(len, state)
	}
}
fn get<'a>(cache: &'a [PrimCache], o: &Obj) -> &'a PrimImpl {
	&cache.at(o.idx).o
}