use std::any::TypeId;
use crate::utils::{convert_bytes_to_value, convert_value_to_bytes};
use crate::vector::{IntVector4, Vector4};
use bytemuck::{Pod, Zeroable};
use imgui::ImString;
use log::error;
#[repr(C)]
#[derive(Debug, Copy, Clone, Pod, Zeroable)]
pub struct Uniforms {
pub resolution: Vector4,
pub time: f32,
pub time_delta: f32,
pub frame_num: u32,
pub mouse_info: Vector4,
pub num_textures: u32,
pub date: IntVector4,
}
impl Uniforms {
pub fn new() -> Uniforms {
Uniforms {
resolution: Vector4::zero(),
time: 0.0,
time_delta: 0.0,
frame_num: 0,
mouse_info: Vector4::zero(),
num_textures: 0,
date: IntVector4::zero(),
}
}
}
pub trait UserUniform {
fn size(&self) -> usize;
fn name(&self) -> String;
fn bytes(&self) -> Vec<u8>;
fn type_id(&self) -> std::any::TypeId;
fn copy(&self) -> Box<dyn UserUniform>;
fn set(&mut self, bytes: &[u8]);
}
#[repr(C)]
pub struct TypedUniform<RealType, BoundType> {
value: BoundType,
name: String,
phantom: std::marker::PhantomData<RealType>,
}
impl<RealType: 'static, BoundType: 'static> TypedUniform<RealType, BoundType> {
fn new(value: BoundType, name: String) -> Self {
Self {
value,
name,
phantom: std::marker::PhantomData,
}
}
}
impl<RealType: 'static, BoundType: 'static + Clone + Copy> UserUniform
for TypedUniform<RealType, BoundType>
{
fn size(&self) -> usize {
std::mem::size_of_val(&self.value)
}
fn name(&self) -> String {
self.name.to_string()
}
fn bytes(&self) -> Vec<u8> {
convert_value_to_bytes(self.value.clone())
}
fn type_id(&self) -> std::any::TypeId {
return std::any::TypeId::of::<TypedUniform<RealType, BoundType>>();
}
fn copy(&self) -> Box<dyn UserUniform> {
Box::new(TypedUniform::<RealType, BoundType>::new(
self.value.clone(),
self.name.clone(),
))
}
fn set(&mut self, bytes: &[u8]) {
self.value = convert_bytes_to_value(bytes).unwrap();
}
}
pub fn load_uniforms_from_json(data: &json::JsonValue) -> Vec<Box<dyn UserUniform>> {
let mut uniforms: Vec<Box<dyn UserUniform>> = Vec::new();
let uniforms_json = &data["uniforms"];
if !uniforms_json.is_null() {
let entries = uniforms_json.entries();
for entry in entries {
let name = entry.0;
let mut array_itr = entry.1.members();
let type_str = array_itr.next().unwrap().as_str().unwrap();
let value = array_itr.next().unwrap();
if type_str == "f32" {
uniforms.push(Box::new(TypedUniform::<f32, f32>::new(
value.as_f32().unwrap(),
String::from(name),
)));
} else if type_str == "f64" {
uniforms.push(Box::new(TypedUniform::<f64, f64>::new(
value.as_f64().unwrap(),
String::from(name),
)));
} else if type_str == "u32" {
uniforms.push(Box::new(TypedUniform::<u32, u32>::new(
value.as_u32().unwrap(),
String::from(name),
)));
} else if type_str == "u64" {
uniforms.push(Box::new(TypedUniform::<u64, u64>::new(
value.as_u64().unwrap(),
String::from(name),
)));
} else if type_str == "i32" {
uniforms.push(Box::new(TypedUniform::<i32, i32>::new(
value.as_i32().unwrap(),
String::from(name),
)));
} else if type_str == "i64" {
uniforms.push(Box::new(TypedUniform::<i64, i64>::new(
value.as_i64().unwrap(),
String::from(name),
)));
} else if type_str == "bool" {
uniforms.push(Box::new(TypedUniform::<bool, u32>::new(
value.as_bool().unwrap() as u32,
String::from(name),
)));
} else {
error!("Uniform with invalid type {} found, ignoring.", type_str);
}
}
}
uniforms
}
pub fn update_user_uniform_ui(ui: &imgui::Ui, uniform: &mut Box<dyn UserUniform>) {
if uniform.type_id() == TypeId::of::<TypedUniform<f32, f32>>() {
let mut value: f32 = convert_bytes_to_value(&uniform.bytes()).unwrap();
ui.input_float(&ImString::from(uniform.name()), &mut value)
.build();
uniform.set(&convert_value_to_bytes(value));
} else if uniform.type_id() == TypeId::of::<TypedUniform<i32, i32>>() {
let mut value: i32 = convert_bytes_to_value(&uniform.bytes()).unwrap();
ui.input_int(&ImString::from(uniform.name()), &mut value)
.build();
uniform.set(&convert_value_to_bytes(value));
} else if uniform.type_id() == TypeId::of::<TypedUniform<u32, u32>>() {
let value: u32 = convert_bytes_to_value(&uniform.bytes()).unwrap();
let mut value_i32 = value as i32;
ui.input_int(&ImString::from(uniform.name()), &mut value_i32)
.build();
uniform.set(&convert_value_to_bytes(value));
}
else if uniform.type_id() == TypeId::of::<TypedUniform<f64, f64>>() {
let mut value: f32 = convert_bytes_to_value(&uniform.bytes()).unwrap();
ui.input_float(&ImString::from(uniform.name()), &mut value)
.build();
uniform.set(&convert_value_to_bytes(value as f64));
} else if uniform.type_id() == TypeId::of::<TypedUniform<i64, i64>>() {
let mut value: i32 = convert_bytes_to_value(&uniform.bytes()).unwrap();
ui.input_int(&ImString::from(uniform.name()), &mut value)
.build();
uniform.set(&convert_value_to_bytes(value as i64));
} else if uniform.type_id() == TypeId::of::<TypedUniform<u64, u64>>() {
let value: u32 = convert_bytes_to_value(&uniform.bytes()).unwrap();
let mut value_i32 = value as i32;
ui.input_int(&ImString::from(uniform.name()), &mut value_i32)
.build();
uniform.set(&convert_value_to_bytes(value_i32 as u64));
} else if uniform.type_id() == TypeId::of::<TypedUniform<bool, u32>>() {
let value: u32 = convert_bytes_to_value(&uniform.bytes()).unwrap();
let mut value_bool = value != 0;
ui.checkbox(&ImString::from(uniform.name()), &mut value_bool);
uniform.set(&convert_value_to_bytes(value_bool as u32));
}
}