macro_rules! impl_material_body {
($inner:ident) => {
fn fragment_shader_source(&self, lights: &[&dyn Light]) -> String {
self.$inner().fragment_shader_source(lights)
}
fn use_uniforms(&self, program: &Program, viewer: &dyn Viewer, lights: &[&dyn Light]) {
self.$inner().use_uniforms(program, viewer, lights)
}
fn render_states(&self) -> RenderStates {
self.$inner().render_states()
}
fn material_type(&self) -> MaterialType {
self.$inner().material_type()
}
fn id(&self) -> EffectMaterialId {
self.$inner().id()
}
};
}
use crate::renderer::*;
pub use three_d_asset::material::{
GeometryFunction, LightingModel, NormalDistributionFunction, PbrMaterial as CpuMaterial,
};
mod color_material;
#[doc(inline)]
pub use color_material::*;
mod depth_material;
#[doc(inline)]
pub use depth_material::*;
mod intersection_material;
#[doc(inline)]
pub use intersection_material::*;
mod normal_material;
#[doc(inline)]
pub use normal_material::*;
mod orm_material;
#[doc(inline)]
pub use orm_material::*;
mod position_material;
#[doc(inline)]
pub use position_material::*;
mod uv_material;
#[doc(inline)]
pub use uv_material::*;
mod physical_material;
#[doc(inline)]
pub use physical_material::*;
mod deferred_physical_material;
#[doc(inline)]
pub use deferred_physical_material::*;
mod skybox_material;
#[doc(inline)]
pub(in crate::renderer) use skybox_material::*;
mod wireframe_material;
#[doc(inline)]
pub(in crate::renderer) use wireframe_material::*;
mod isosurface_material;
#[doc(inline)]
pub use isosurface_material::*;
use std::{ops::Deref, sync::Arc};
#[derive(Clone)]
pub struct Texture2DRef {
pub texture: Arc<Texture2D>,
pub transformation: Mat3,
}
impl Texture2DRef {
pub fn from_cpu_texture(context: &Context, cpu_texture: &CpuTexture) -> Self {
Self {
texture: Arc::new(Texture2D::new(context, cpu_texture)),
transformation: Mat3::identity(),
}
}
pub fn from_texture(texture: Texture2D) -> Self {
Self {
texture: Arc::new(texture),
transformation: Mat3::identity(),
}
}
}
impl std::ops::Deref for Texture2DRef {
type Target = Texture2D;
fn deref(&self) -> &Self::Target {
&self.texture
}
}
impl std::convert::From<Texture2D> for Texture2DRef {
fn from(texture: Texture2D) -> Self {
Self::from_texture(texture)
}
}
impl std::convert::From<Arc<Texture2D>> for Texture2DRef {
fn from(texture: Arc<Texture2D>) -> Self {
Self {
texture,
transformation: Mat3::identity(),
}
}
}
#[derive(Clone, Copy, PartialEq, PartialOrd, Ord, Eq, Debug)]
pub enum MaterialType {
Opaque,
Transparent,
Deferred,
}
pub trait Material {
fn fragment_shader_source(&self, lights: &[&dyn Light]) -> String;
fn id(&self) -> EffectMaterialId;
fn use_uniforms(&self, program: &Program, viewer: &dyn Viewer, lights: &[&dyn Light]);
fn render_states(&self) -> RenderStates;
fn material_type(&self) -> MaterialType;
}
pub trait FromCpuMaterial: std::marker::Sized {
fn from_cpu_material(context: &Context, cpu_material: &CpuMaterial) -> Self;
}
pub trait FromCpuVoxelGrid: std::marker::Sized {
fn from_cpu_voxel_grid(context: &Context, cpu_voxel_grid: &CpuVoxelGrid) -> Self;
}
impl<T: Material + ?Sized> Material for &T {
impl_material_body!(deref);
}
impl<T: Material + ?Sized> Material for &mut T {
impl_material_body!(deref);
}
impl<T: Material> Material for Box<T> {
impl_material_body!(as_ref);
}
impl<T: Material> Material for std::rc::Rc<T> {
impl_material_body!(as_ref);
}
impl<T: Material> Material for std::sync::Arc<T> {
impl_material_body!(as_ref);
}
impl<T: Material> Material for std::cell::RefCell<T> {
impl_material_body!(borrow);
}
impl<T: Material> Material for std::sync::RwLock<T> {
fn fragment_shader_source(&self, lights: &[&dyn Light]) -> String {
self.read().unwrap().fragment_shader_source(lights)
}
fn use_uniforms(&self, program: &Program, viewer: &dyn Viewer, lights: &[&dyn Light]) {
self.read().unwrap().use_uniforms(program, viewer, lights)
}
fn render_states(&self) -> RenderStates {
self.read().unwrap().render_states()
}
fn material_type(&self) -> MaterialType {
self.read().unwrap().material_type()
}
fn id(&self) -> EffectMaterialId {
self.read().unwrap().id()
}
}
fn is_transparent(cpu_material: &CpuMaterial) -> bool {
cpu_material.albedo.a != 255
|| cpu_material
.albedo_texture
.as_ref()
.map(|t| match &t.data {
TextureData::RgbaU8(data) => data.iter().any(|d| d[3] != 255),
TextureData::RgbaF16(data) => data.iter().any(|d| d[3] < f16::from_f32(0.99)),
TextureData::RgbaF32(data) => data.iter().any(|d| d[3] < 0.99),
_ => false,
})
.unwrap_or(false)
}