use ecs::Component; use crate::color::Color; use crate::data_types::dimens::Dimens; use crate::texture::{Id as TextureId, Texture}; #[derive(Debug, Clone, Component)] pub struct Material { ambient: Color, diffuse: Color, specular: Color, ambient_map: TextureId, diffuse_map: TextureId, specular_map: TextureId, textures: Vec, shininess: f32, } impl Material { #[must_use] pub fn ambient(&self) -> &Color { &self.ambient } #[must_use] pub fn diffuse(&self) -> &Color { &self.diffuse } #[must_use] pub fn specular(&self) -> &Color { &self.specular } #[must_use] pub fn ambient_map(&self) -> &TextureId { &self.ambient_map } #[must_use] pub fn diffuse_map(&self) -> &TextureId { &self.diffuse_map } #[must_use] pub fn specular_map(&self) -> &TextureId { &self.specular_map } #[must_use] pub fn textures(&self) -> &[Texture] { &self.textures } #[must_use] pub fn shininess(&self) -> f32 { self.shininess } } /// [`Material`] builder. #[derive(Debug, Clone)] pub struct Builder { ambient: Option>, diffuse: Option>, specular: Option>, ambient_map: Option, diffuse_map: Option, specular_map: Option, textures: Vec, shininess: f32, } impl Builder { #[must_use] pub fn new() -> Self { Self { ambient: None, diffuse: None, specular: None, ambient_map: None, diffuse_map: None, specular_map: None, textures: Vec::new(), shininess: 32.0, } } #[must_use] pub fn ambient(mut self, ambient: Color) -> Self { self.ambient = Some(ambient); self } #[must_use] pub fn diffuse(mut self, diffuse: Color) -> Self { self.diffuse = Some(diffuse); self } #[must_use] pub fn specular(mut self, specular: Color) -> Self { self.specular = Some(specular); self } #[must_use] pub fn ambient_map(mut self, ambient_map: TextureId) -> Self { self.ambient_map = Some(ambient_map); self } #[must_use] pub fn diffuse_map(mut self, diffuse_map: TextureId) -> Self { self.diffuse_map = Some(diffuse_map); self } #[must_use] pub fn specular_map(mut self, specular_map: TextureId) -> Self { self.specular_map = Some(specular_map); self } #[must_use] pub fn textures(mut self, textures: impl IntoIterator) -> Self { self.textures = textures.into_iter().collect(); self } #[must_use] pub fn texture(mut self, texture: Texture) -> Self { self.textures.push(texture); self } #[must_use] pub fn shininess(mut self, shininess: f32) -> Self { self.shininess = shininess; self } /// Builds a new [`Material`]. /// /// # Panics /// Will panic if no ambient map, diffuse map or specular map is set. #[must_use] pub fn build(mut self) -> Material { let ambient_map = self.ambient_map.unwrap_or_else(|| { let texture = create_1x1_white_texture(); let texture_id = texture.id(); self.textures.push(texture); texture_id }); let diffuse_map = self.diffuse_map.unwrap_or_else(|| { let texture = create_1x1_white_texture(); let texture_id = texture.id(); self.textures.push(texture); texture_id }); let specular_map = self.specular_map.unwrap_or_else(|| { let texture = create_1x1_white_texture(); let texture_id = texture.id(); self.textures.push(texture); texture_id }); Material { ambient: self.ambient.unwrap_or_default(), diffuse: self.diffuse.unwrap_or_default(), specular: self.specular.unwrap_or_default(), ambient_map, diffuse_map, specular_map, textures: self.textures, shininess: self.shininess, } } } impl Default for Builder { fn default() -> Self { Self::new() } } fn create_1x1_white_texture() -> Texture { Texture::new_from_color(&Dimens { width: 1, height: 1 }, &Color::WHITE_U8) }