use crate::parsing::FromRanges;
use bytemuck::*;
macro_rules! extract {
($expression:expr, $(
$(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? => $output:expr
),+ $(,)?) => {
match $expression {
$($( $pattern )|+ $( if $guard )? => Some($output),)+
_ => None
}
}
}
pub type Color = [f32; 4];
#[repr(u32)]
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, NoUninit)]
pub enum ShaderBool {
False = 0,
True,
}
impl ShaderBool {
pub fn is_true(&self) -> bool {
matches!(self, ShaderBool::True)
}
}
pub type EventCode = u32;
#[derive(Debug, Clone)]
pub struct BoundedInput<T>
where
T: Clone + Copy,
{
pub current: T,
pub min: T,
pub max: T,
pub default: T,
}
#[derive(Debug, Clone)]
pub struct DiscreteInput<T>
where
T: Clone + Copy + PartialEq,
{
pub current: T,
pub default: T,
}
#[derive(Debug)]
pub struct MutInput<'a> {
pub(crate) inner: &'a mut InputType,
}
impl<'a> MutInput<'a> {
pub fn variant(&self) -> InputVariant {
InputVariant::from(&*self.inner)
}
pub fn texture_status(&mut self) -> Option<TextureStatus> {
extract!(self.inner, InputType::Image(i) => *i)
}
pub fn as_float(&mut self) -> Option<&mut BoundedInput<f32>> {
extract!(self.inner, InputType::Float(i) => i)
}
pub fn as_int(&mut self) -> Option<MutInputInt<'_>> {
extract!(self.inner, InputType::Int(value, labels) => MutInputInt { value, labels})
}
pub fn as_point(&mut self) -> Option<&mut BoundedInput<[f32; 2]>> {
extract!(self.inner, InputType::Point(i) => i)
}
pub fn as_bool(&mut self) -> Option<&mut DiscreteInput<ShaderBool>> {
extract!(self.inner, InputType::Bool(i) => i)
}
pub fn as_color(&mut self) -> Option<&mut DiscreteInput<Color>> {
extract!(self.inner, InputType::Color(i) => i)
}
pub fn as_unknown_bytes(&mut self) -> &mut [u8] {
self.inner.as_bytes_mut()
}
pub fn copy_into(&mut self, other: &mut Self) -> bool {
match (&mut self.inner, &mut other.inner) {
(InputType::Int(s, s_list), InputType::Int(o, o_list)) => {
if let (Some(s_list), Some(o_list)) = (s_list, o_list) {
if s_list.iter().find(|(_, val)| s.current == *val)
== o_list.iter().find(|(_, val)| s.current == *val)
{
o.current = s.current;
return true;
}
}
if s.current <= o.max && s.current >= o.min && s.default == o.default {
o.current = s.current;
true
} else {
false
}
}
(InputType::Float(s), InputType::Float(o)) => {
if s.current <= o.max && s.current >= o.min && s.default == o.default {
o.current = s.current;
true
} else {
false
}
}
(InputType::Point(s), InputType::Point(o)) => {
if s.current <= o.max && s.current >= o.min && s.default == o.default {
o.current = s.current;
true
} else {
false
}
}
(InputType::Color(s), InputType::Color(o)) => {
o.current = s.current;
true
}
(InputType::Bool(s), InputType::Bool(o)) => {
o.current = s.current;
true
}
(InputType::Image(s), InputType::Image(o)) => {
*o = *s;
true
}
_ => false,
}
}
}
pub struct MutInputInt<'a> {
pub value: &'a mut BoundedInput<i32>,
pub labels: &'a mut Option<Vec<(String, i32)>>,
}
pub type AudioFftInput = (TextureStatus, Option<u32>);
pub type AudioInput = (TextureStatus, Option<u32>);
#[derive(Debug, Clone, Copy, Default)]
pub enum TextureStatus {
#[default]
Uninit,
Loaded { width: u32, height: u32 },
}
#[derive(Debug, Clone)]
pub struct RawBytes {
pub inner: Vec<u8>,
}
impl FromRanges<f32> for BoundedInput<f32> {
fn from_ranges(min: Option<f32>, max: Option<f32>, default: Option<f32>) -> Self {
let default_f32 = default.map_or(0.0, |v| v);
let range = f32::abs(default_f32).max(1.0) * 10.0;
let min_f32 = min.map_or(-range, |v| v);
let max_f32 = max.map_or(range, |v| v);
Self {
current: default_f32,
min: min_f32,
max: max_f32,
default: default_f32,
}
}
}
impl FromRanges<EventCode> for DiscreteInput<EventCode> {
fn from_ranges(
_min: Option<EventCode>,
_max: Option<EventCode>,
_default: Option<EventCode>,
) -> Self {
Self {
current: 0,
default: 0,
}
}
}
impl FromRanges<i32> for BoundedInput<i32> {
fn from_ranges(min: Option<i32>, max: Option<i32>, default: Option<i32>) -> Self {
let default_i32 = default.unwrap_or(0);
let range = default_i32.abs().max(1) * 10;
let min_i32 = min.unwrap_or(-range);
let max_i32 = max.unwrap_or(range);
Self {
current: default_i32,
min: min_i32,
max: max_i32,
default: default_i32,
}
}
}
impl FromRanges<[f32; 2]> for BoundedInput<[f32; 2]> {
fn from_ranges(
min: Option<[f32; 2]>,
max: Option<[f32; 2]>,
default: Option<[f32; 2]>,
) -> Self {
let default_f32 = default.unwrap_or([0.0, 0.0]);
let range_x = default_f32[0].abs().max(1.0) * 10.0;
let range_y = default_f32[1].abs().max(1.0) * 10.0;
let min_x = min.unwrap_or([-range_x, -range_y]);
let max_x = max.unwrap_or([range_x, range_y]);
Self {
current: default_f32,
min: min_x,
max: max_x,
default: default_f32,
}
}
}
impl FromRanges<ShaderBool> for DiscreteInput<ShaderBool> {
fn from_ranges(
_min: Option<ShaderBool>,
_max: Option<ShaderBool>,
default: Option<ShaderBool>,
) -> Self {
let default_bool = default.unwrap_or(ShaderBool::False);
Self {
current: default_bool,
default: default_bool,
}
}
}
impl FromRanges<[f32; 4]> for DiscreteInput<[f32; 4]> {
fn from_ranges(
_min: Option<[f32; 4]>,
_max: Option<[f32; 4]>,
default: Option<[f32; 4]>,
) -> Self {
let default_f32 = default.unwrap_or([0.0, 0.0, 0.0, 1.0]);
Self {
current: default_f32,
default: default_f32,
}
}
}
#[derive(Debug, Clone)]
pub enum InputType {
Float(BoundedInput<f32>),
Int(BoundedInput<i32>, Option<Vec<(String, i32)>>),
Point(BoundedInput<[f32; 2]>),
Bool(DiscreteInput<ShaderBool>),
Color(DiscreteInput<Color>),
Image(TextureStatus),
RawBytes(RawBytes),
}
pub trait TryAsMut<T> {
fn try_as_mut(&mut self) -> Option<&mut T>;
}
impl TryAsMut<f32> for InputType {
fn try_as_mut(&mut self) -> Option<&mut f32> {
extract!(self, InputType::Float(f) => &mut f.current)
}
}
impl TryAsMut<i32> for InputType {
fn try_as_mut(&mut self) -> Option<&mut i32> {
extract!(self, InputType::Int(i, _) => &mut i.current)
}
}
impl TryAsMut<[f32; 2]> for InputType {
fn try_as_mut(&mut self) -> Option<&mut [f32; 2]> {
extract!(self, InputType::Point(p) => &mut p.current)
}
}
impl TryAsMut<ShaderBool> for InputType {
fn try_as_mut(&mut self) -> Option<&mut ShaderBool> {
extract!(self, InputType::Bool(b) => &mut b.current)
}
}
impl TryAsMut<Color> for InputType {
fn try_as_mut(&mut self) -> Option<&mut Color> {
extract!(self, InputType::Color(c) => &mut c.current)
}
}
impl InputType {
pub fn is_stored_as_texture(&self) -> bool {
matches!(self, Self::Image(_))
}
pub fn as_mut<T>(&mut self) -> Option<&mut T>
where
InputType: TryAsMut<T>,
{
self.try_as_mut()
}
pub fn texture_status(&self) -> Option<&TextureStatus> {
match self {
Self::Image(s) => Some(s),
_ => None,
}
}
pub fn as_bytes_mut(&mut self) -> &mut [u8] {
match self {
Self::Float(v) => bytes_of_mut(&mut v.current),
Self::Int(v, _) => bytes_of_mut(&mut v.current),
Self::Point(v) => bytes_of_mut(&mut v.current),
Self::Color(v) => bytes_of_mut(&mut v.current),
Self::RawBytes(v) => v.inner.as_mut_slice(),
_ => &mut [],
}
}
pub fn as_bytes(&self) -> &[u8] {
match self {
Self::Float(v) => bytes_of(&v.current),
Self::Int(v, _) => bytes_of(&v.current),
Self::Point(v) => bytes_of(&v.current),
Self::Bool(v) => bytes_of(&v.current),
Self::Color(v) => bytes_of(&v.current),
Self::RawBytes(v) => v.inner.as_slice(),
_ => &[],
}
}
}
impl<'a> From<&'a mut InputType> for MutInput<'a> {
fn from(val: &'a mut InputType) -> Self {
MutInput { inner: val }
}
}
impl std::fmt::Display for InputType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
InputType::Float(_) => "Float",
InputType::Int(_, _) => "Int",
InputType::Point(_) => "Point",
InputType::Bool(_) => "Bool",
InputType::Color(_) => "Color",
InputType::Image(_) => "Image",
InputType::RawBytes(_) => "Raw Bytes",
};
write!(f, "{s}")
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum InputVariant {
Float,
Int,
Point,
Bool,
Color,
Image,
Bytes,
}
impl From<&InputType> for InputVariant {
fn from(variant: &InputType) -> InputVariant {
match variant {
InputType::Float(_) => InputVariant::Float,
InputType::Int(_, _) => InputVariant::Int,
InputType::Point(_) => InputVariant::Point,
InputType::Bool(_) => InputVariant::Bool,
InputType::Color(_) => InputVariant::Color,
InputType::Image(_) => InputVariant::Image,
InputType::RawBytes(_) => InputVariant::Bytes,
}
}
}