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 crate::lib::*;

macro_rules! APPLICATOR {
	($n: ident, $($t: ident),+) => {
		pub trait $n<$($t),+> {
			#![allow(dead_code)]
			fn apply(&self, _: unsafe fn($($t),+));
		}
		#[allow(unused_parens)]
		impl<$($t: GLPrimitive),+> $n<$($t),+> for ($($t),+) {
			fn apply(&self, func: unsafe fn($($t),+)) {
				let ($($t),+) = self;
				GL!(func($(*$t),+));
			}
		}
	}
}

APPLICATOR!(UnpackTuple0, t);
APPLICATOR!(UnpackTuple1, t0, t1);
APPLICATOR!(UnpackTuple2, t0, t1, t2);
APPLICATOR!(UnpackTuple3, t0, t1, t2, t3);
APPLICATOR!(UnpackTuple4, t0, t1, t2, t3, t4);
APPLICATOR!(UnpackTuple5, t0, t1, t2, t3, t4, t5);

pub fn states_map() -> &'static mut HashMap<usize, (bool, bool)> {
	LocalStatic!(HashMap<usize, (bool, bool)>)
}

macro_rules! FUNC {
($m: ident, $n: ident, $($t: ty),+) => {
	pub struct $n;
	#[allow(unused_parens)]
	impl $n {
		fn state() -> &'static mut ($($t),+) {
			LocalStatic!(($($t),+), { ($(0 as $t),+) })
		}
		fn saved_state() -> &'static mut ($($t),+) {
			LocalStatic!(($($t),+), { ($(0 as $t),+) })
		}

		pub fn Set(state: ($($t),+)) {
			let last_s = Self::state();
			debug_assert!({
				states_map().entry($m::$n as *const () as usize).or_insert_with(|| { ASSERT!(state != *last_s, "First call to GL::{}::Set() must not have all zeros as arguments", stringify!($n)); (false, false) });
				true
			});
			if *last_s != state {
				*last_s = state;
				state.apply($m::$n);
				DEBUG!("Set GL::{}({state:?})", stringify!($n));
			}
		}

		pub fn Save() {
			debug_assert!({
				let (valid, _) = states_map().get_mut(&($m::$n as *const () as usize)).explain_err(|| format!("GL::{}::Save() with default state, nothing to save", stringify!($n))).fail();
				*valid = true;
				true
			});
			*Self::saved_state() = *Self::state();
		}

		pub fn Restore() {
			ASSERT!({
					let (valid, _) = states_map().entry($m::$n as *const () as usize).or_insert((false, false));
					let r = *valid;
					*valid = false;
					r
				},
				"GL::{}::Restore() call not paired with Set()",
				stringify!($n)
			);
			let state = Self::state();
			let prev_s = Self::saved_state();
			if state != prev_s {
				*state = *prev_s;
				state.apply($m::$n);
				DEBUG!("Restored GL::{}({state:?})", stringify!($n));
			}
		}
	}
}}

pub trait State {
	fn gl_enable(t: GLenum) {
		GL!(gl::Enable(t))
	}
	fn gl_disable(t: GLenum) {
		GL!(gl::Disable(t))
	}
}

pub fn overflow_map() -> &'static mut HashMap<GLenum, i32> {
	LocalStatic!(HashMap<GLenum, i32>)
}

macro_rules! SWITCH {
	($n: ident) => {
		impl State for $n {}
		SWITCH_IMPL!($n, 0);
	};
	($n: ident, DEFAULT_TRUE) => {
		impl State for $n {}
		SWITCH_IMPL!($n, 18446744073709551615);
	};
	($n: ident, $e: expr, $d: expr, $i: literal) => {
		impl State for $n {
			fn gl_enable(_: GLenum) {
				GL!($e)
			}
			fn gl_disable(_: GLenum) {
				GL!($d)
			}
		}
		SWITCH_IMPL!($n, $i);
	};
	($n: ident, $e: expr, $d: expr) => {
		SWITCH!($n, $e, $d, 0);
	};
	($n: ident, $e: expr, $d: expr, DEFAULT_TRUE) => {
		SWITCH!($n, $e, $d, 18446744073709551615);
	};
}

macro_rules! SWITCH_IMPL {
	($n: ident, $i: literal) => {
		pub struct $n;
		impl $n {
			fn state() -> &'static mut u64 {
				LocalStatic!(u64, { $i })
			}

			pub fn Enable() {
				let state = Self::state();
				if (*state & 1u64) != 1u64 {
					Self::gl_enable(gl::$n);
					DEBUG!("Enabled GL::{}", stringify!($n));
					*state |= 1u64;
				}
			}

			pub fn Disable() {
				let state = Self::state();
				if (*state & 1u64) != 0u64 {
					Self::gl_disable(gl::$n);
					DEBUG!("Disabled GL::{}", stringify!($n));
					*state &= !1u64;
				}
			}

			pub fn Save() {
				debug_assert!({
					let v = overflow_map().entry(gl::$n).or_insert(0);
					*v = 64.min(*v + 1);
					true
				});

				let state = Self::state();
				*state = (*state & 1u64) | (*state << 1);
			}

			pub fn Restore() {
				ASSERT!(
					{
						let v = overflow_map().entry(gl::$n).or_insert(0);
						*v -= 1;
						*v >= 0
					},
					"No state for GL::{} in stack",
					stringify!($n)
				);

				let state = Self::state();
				let s = *state & 1u64;
				*state >>= 1;
				if s != (*state & 1u64) {
					DEBUG!("Restored GL::{}({s})", stringify!($n));
					if *state == 0u64 {
						Self::gl_disable(gl::$n);
					} else {
						Self::gl_enable(gl::$n);
					}
				}
			}
		}
	};
}

pub trait GLPrimitive: Copy {}
impl_trait_for!(GLPrimitive = u8, i8, u16, i16, u32, i32, u64, i64, f32, f64, usize, isize);