use crate::model::vs as model_vs;
use cgmath::{Vector3, Zero};
pub struct DirectionalLight {
pub direction: Vector3<f32>,
pub color: LightColor,
}
impl Default for DirectionalLight {
fn default() -> Self {
Self {
direction: Vector3::zero(),
color: LightColor::default(),
}
}
}
pub struct PointLight {
pub position: Vector3<f32>,
pub color: LightColor,
pub attenuation: PointLightAttenuation,
}
impl Default for PointLight {
fn default() -> Self {
Self {
position: Vector3::zero(),
color: LightColor::default(),
attenuation: PointLightAttenuation::default(),
}
}
}
pub struct LightColor {
pub ambient: Vector3<f32>,
pub diffuse: Vector3<f32>,
pub specular: Vector3<f32>,
}
impl Default for LightColor {
fn default() -> Self {
LightColor {
ambient: Vector3::zero(),
diffuse: Vector3::zero(),
specular: Vector3::zero(),
}
}
}
pub struct PointLightAttenuation {
pub constant: f32,
pub linear: f32,
pub quadratic: f32,
}
impl Default for PointLightAttenuation {
fn default() -> Self {
Self {
constant: 1.0,
linear: 0.09,
quadratic: 0.032,
}
}
}
pub struct LightState {
pub directional: FixedVec<DirectionalLight>,
pub point: FixedVec<PointLight>,
}
impl LightState {
pub(crate) fn new() -> Self {
Self {
directional: FixedVec::<DirectionalLight>::new(),
point: FixedVec::<PointLight>::new(),
}
}
}
const LIGHT_COUNT: usize = 100;
pub struct FixedVec<T> {
pub(crate) data: [T; LIGHT_COUNT],
len: usize,
}
impl FixedVec<DirectionalLight> {
pub(crate) fn to_shader_value(&self) -> (i32, [model_vs::ty::DirectionalLight; LIGHT_COUNT]) {
let result = array_init::array_init(|i| {
let light = &self.data[i];
model_vs::ty::DirectionalLight {
direction_x: light.direction.x,
direction_y: light.direction.y,
direction_z: light.direction.z,
color_ambient_r: light.color.ambient.x,
color_ambient_g: light.color.ambient.y,
color_ambient_b: light.color.ambient.z,
color_diffuse_r: light.color.diffuse.x,
color_diffuse_g: light.color.diffuse.x,
color_diffuse_b: light.color.diffuse.z,
color_specular_r: light.color.specular.x,
color_specular_g: light.color.specular.y,
color_specular_b: light.color.specular.z,
}
});
(self.len() as i32, result)
}
}
impl<T: Default> FixedVec<T> {
pub(crate) fn new() -> Self {
Self {
data: array_init::array_init(|_| T::default()),
len: 0,
}
}
}
impl<T> FixedVec<T> {
pub fn as_slice(&self) -> &[T] {
&self.data[..self.len]
}
pub fn as_mut_slice(&mut self) -> &mut [T] {
&mut self.data[..self.len]
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn push(&mut self, t: T) {
assert!(self.len() < LIGHT_COUNT);
self.data[self.len] = t;
self.len += 1;
}
pub fn pop(&mut self) {
assert!(self.len > 0);
self.len -= 1;
}
}
impl<T> std::ops::Index<usize> for FixedVec<T> {
type Output = T;
fn index(&self, index: usize) -> &T {
assert!(index < self.len());
&self.data[index]
}
}
impl<T> std::ops::IndexMut<usize> for FixedVec<T> {
fn index_mut(&mut self, index: usize) -> &mut T {
assert!(index < self.len());
&mut self.data[index]
}
}