use glam::Vec3;
use crate::color::Color;
use crate::shader::{ShaderHandle, UniformBlock};
#[derive(Clone, Debug)]
pub enum Material {
Matte { base: Color },
Glossy {
base: Color,
specular: f32,
shininess: f32,
},
Flat { color: Color },
Custom {
shader: ShaderHandle,
uniforms: UniformBlock,
},
}
impl Material {
pub fn matte(base: Color) -> Self {
Material::Matte { base }
}
pub fn flat(color: Color) -> Self {
Material::Flat { color }
}
pub fn glossy(base: Color) -> Self {
Material::Glossy {
base,
specular: 0.5,
shininess: 32.0,
}
}
}
impl Default for Material {
fn default() -> Self {
Material::Matte {
base: Color::srgb_u8(214, 220, 230),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum SizeMode {
#[default]
ScreenSpace,
World,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum PointShape {
#[default]
Circle,
Square,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct PointStyle {
pub size: f32,
pub shape: PointShape,
pub size_mode: SizeMode,
}
impl Default for PointStyle {
fn default() -> Self {
Self {
size: 5.0,
shape: PointShape::Circle,
size_mode: SizeMode::ScreenSpace,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum LinePattern {
#[default]
Solid,
Dashed,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct LineStyle {
pub width: f32,
pub pattern: LinePattern,
pub size_mode: SizeMode,
}
impl Default for LineStyle {
fn default() -> Self {
Self {
width: 1.5,
pattern: LinePattern::Solid,
size_mode: SizeMode::ScreenSpace,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct LightRig {
pub key_direction: Vec3,
pub key_color: Color,
pub key_intensity: f32,
pub sky_color: Color,
pub ground_color: Color,
pub ambient: f32,
}
impl Default for LightRig {
fn default() -> Self {
Self {
key_direction: Vec3::new(0.4, 0.7, 0.2).normalize(),
key_color: Color::srgb_u8(255, 255, 255),
key_intensity: 1.0,
sky_color: Color::srgb_u8(236, 242, 255),
ground_color: Color::srgb_u8(140, 144, 150),
ambient: 0.35,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct GridPlanes {
pub xy: bool,
pub xz: bool,
pub yz: bool,
}
impl GridPlanes {
pub const NONE: GridPlanes = GridPlanes {
xy: false,
xz: false,
yz: false,
};
pub const XZ: GridPlanes = GridPlanes {
xy: false,
xz: true,
yz: false,
};
}
impl Default for GridPlanes {
fn default() -> Self {
GridPlanes::XZ
}
}
#[derive(Clone, Copy, Debug, PartialEq, Default)]
pub struct AxisBounds {
pub x: Option<(f32, f32)>,
pub y: Option<(f32, f32)>,
pub z: Option<(f32, f32)>,
}
impl AxisBounds {
pub(crate) fn axis(&self, i: usize) -> Option<(f32, f32)> {
match i {
0 => self.x,
1 => self.y,
2 => self.z,
_ => None,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct GridSettings {
pub planes: GridPlanes,
pub spacing: f32,
pub extent: f32,
pub subdivisions: u32,
pub color: Color,
pub bounds: AxisBounds,
}
impl Default for GridSettings {
fn default() -> Self {
Self {
planes: GridPlanes::default(),
spacing: 1.0,
extent: 10.0,
subdivisions: 1,
color: Color::srgb_u8a(120, 120, 132, 90),
bounds: AxisBounds::default(),
}
}
}
impl GridSettings {
pub(crate) fn axis_spans(&self) -> [(f32, f32); 3] {
let e = self.extent.max(0.0);
let fb = (-e, e);
std::array::from_fn(|i| {
let (a, b) = self.bounds.axis(i).unwrap_or(fb);
(a.min(b), a.max(b))
})
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct SceneStyle {
pub grid: GridSettings,
pub background: Option<Color>,
pub msaa_samples: u32,
pub show_axes: bool,
}
impl Default for SceneStyle {
fn default() -> Self {
Self {
grid: GridSettings::default(),
background: None,
msaa_samples: 4,
show_axes: true,
}
}
}
impl SceneStyle {
pub fn reference_extent(&self) -> Option<crate::scene::Aabb> {
let draws_grid = self.grid.planes != GridPlanes::NONE && self.grid.extent.max(0.0) > 0.0;
let draws_axes = self.show_axes;
if !draws_grid && !draws_axes {
return None;
}
let spans = self.grid.axis_spans();
let axis_fallback = self.grid.extent.max(self.grid.spacing).max(1.0);
let mut lo = [0.0f32; 3];
let mut hi = [0.0f32; 3];
for i in 0..3 {
let (mut amin, mut amax) = (0.0f32, 0.0f32);
if let Some((bmin, bmax)) = self.grid.bounds.axis(i) {
amin = amin.min(bmin.min(bmax));
amax = amax.max(bmin.max(bmax));
} else {
if draws_grid {
amin = amin.min(spans[i].0);
amax = amax.max(spans[i].1);
}
if draws_axes {
amin = amin.min(-axis_fallback);
amax = amax.max(axis_fallback);
}
}
lo[i] = amin;
hi[i] = amax;
}
let aabb = crate::scene::Aabb::from_points([
glam::Vec3::from_array(lo),
glam::Vec3::from_array(hi),
]);
aabb.is_valid().then_some(aabb)
}
}