use crate::{Material, MaterialAspect, ShortIndex};
#[derive(Debug, Clone)]
pub struct BaseData {
pub rgba: u32,
pub metallic_roughness: u32,
pub emissive_rgb: u32,
pub alpha_etc: u32,
}
impl Default for BaseData {
fn default() -> Self {
0xffffffff_u32.into()
}
}
impl BaseData {
pub fn of_rgba((r, g, b, a): (u8, u8, u8, u8)) -> Self {
let rgba: u32 = (r as u32) | ((g as u32) << 8) | ((b as u32) << 16) | ((a as u32) << 24);
rgba.into()
}
pub fn set_rgba(&mut self, (r, g, b, a): (u8, u8, u8, u8)) {
let rgba: u32 = (r as u32) | ((g as u32) << 8) | ((b as u32) << 16) | ((a as u32) << 24);
self.rgba = rgba;
}
pub fn set_emissive_rgb(&mut self, (r, g, b): (u8, u8, u8)) {
let rgb: u32 = (r as u32) | ((g as u32) << 8) | ((b as u32) << 16);
self.emissive_rgb = rgb
}
pub fn set_mr(&mut self, metallic: f32, roughness: f32) {
let metallic = (metallic * 65535.0) as u32;
let roughness = (roughness * 65535.0) as u32;
self.metallic_roughness = (roughness << 16) | metallic;
}
pub fn metallic_roughness(&self) -> (f32, f32) {
let metallic = self.metallic_roughness & 65535;
let roughness = (self.metallic_roughness >> 16) & 65535;
let metallic = (metallic as f32) / 65535.0;
let roughness = (roughness as f32) / 65535.0;
(metallic, roughness)
}
pub fn rgba_tuple(&self) -> (u8, u8, u8, u8) {
let r = self.rgba & 0xff;
let g = (self.rgba >> 8) & 0xff;
let b = (self.rgba >> 16) & 0xff;
let a = (self.rgba >> 24) & 0xff;
(r as u8, g as u8, b as u8, a as u8)
}
}
impl From<u32> for BaseData {
fn from(rgba: u32) -> Self {
Self {
rgba,
metallic_roughness: 0,
emissive_rgb: 0,
alpha_etc: 0,
}
}
}
#[derive(Debug)]
pub struct BaseMaterial {
base_data: BaseData,
}
impl BaseMaterial {
pub fn of_rgba(rgba: u32) -> Self {
let base_data: BaseData = rgba.into();
Self { base_data }
}
pub fn set_mr(&mut self, metallic: f32, roughness: f32) {
self.base_data.set_mr(metallic, roughness);
}
}
impl Material for BaseMaterial {
fn base_data(&self) -> &BaseData {
&self.base_data
}
}
#[derive(Debug, Default)]
pub struct PbrMaterial {
base_data: BaseData,
base_texture: ShortIndex,
normal_texture: ShortIndex,
mr_texture: ShortIndex,
occlusion_texture: ShortIndex,
emission_texture: ShortIndex,
}
impl PbrMaterial {
pub fn of_rgba(rgba: u32) -> Self {
let base_data: BaseData = rgba.into();
Self {
base_data,
..Default::default()
}
}
pub fn set_rgba(&mut self, (r, g, b, a): (u8, u8, u8, u8)) {
self.base_data.set_rgba((r, g, b, a));
}
pub fn set_emissive_rgb(&mut self, (r, g, b): (u8, u8, u8)) {
self.base_data.set_emissive_rgb((r, g, b));
}
pub fn set_mr(&mut self, metallic: f32, roughness: f32) {
self.base_data.set_mr(metallic, roughness);
}
pub fn set_base_data(&mut self, base_data: &BaseData) {
self.base_data = base_data.clone();
}
pub fn set_texture(&mut self, aspect: MaterialAspect, index: ShortIndex) {
use MaterialAspect::*;
#[allow(unreachable_patterns)]
match aspect {
Color => {
self.base_texture = index;
}
Normal => {
self.normal_texture = index;
}
MetallicRoughness => {
self.mr_texture = index;
}
Occlusion => {
self.occlusion_texture = index;
}
Emission => {
self.emission_texture = index;
}
_ => (),
}
}
}
impl Material for PbrMaterial {
fn base_data(&self) -> &BaseData {
&self.base_data
}
fn texture(&self, aspect: MaterialAspect) -> ShortIndex {
use MaterialAspect::*;
#[allow(unreachable_patterns)]
match aspect {
Color => self.base_texture,
Normal => self.normal_texture,
MetallicRoughness => self.mr_texture,
Occlusion => self.occlusion_texture,
Emission => self.emission_texture,
_ => ShortIndex::none(),
}
}
}