use rin_material::{
Property, Parameter, AlphaType,
texture::{TextureRef, TextureSampler}
};
use mutiny_derive::Material;
use super::{Shader, PropertyChanged, Material, MaterialTransparency, ProgramSettings, std140_data::Data};
use std::cell::RefCell;
#[macro_export]
#[cfg(glsl_debug)]
macro_rules! shader {
($ty: expr, $path: expr, $replacements: expr) => {{
let path = ::std::path::Path::new($path);
let base_path = if path.is_absolute(){
path.parent()
}else{
::std::path::Path::new(file!()).parent()
};
$crate::renderer::Shader::Path{
path: path.to_owned(),
replacements: $replacements,
base_path: base_path.map(|p| p.to_owned()),
includes: Vec::new(),
ty: $ty,
}
}};
($ty: expr, $path: expr) => {{
$crate::shader!($ty, $path, vec![])
}};
}
#[macro_export]
#[cfg(not(glsl_debug))]
macro_rules! shader {
($ty: expr, $path: expr, $replacements: expr) => {{
let path = ::std::path::Path::new($path);
let base_path = if path.is_absolute(){
path.parent()
}else{
::std::path::Path::new(file!()).parent()
};
$crate::renderer::Shader::Source{
include_name: $path.to_owned(),
source: include_str!($path).to_owned(),
replacements: $replacements,
base_path: base_path.map(|p| p.to_owned()),
includes: Vec::new(),
ty: $ty,
}
}};
($ty: expr, $path: expr) => {{
$crate::shader!($ty, $path, vec![])
}};
}
#[macro_export]
macro_rules! vertex_shader {
($path: expr, $replacements: expr) => {
$crate::shader!(rin::gl::VERTEX_SHADER, $path, $replacements)
};
($path: expr) => {
$crate::shader!(rin::gl::VERTEX_SHADER, $path)
};
}
#[macro_export]
macro_rules! fragment_shader {
($path: expr, $replacements: expr) => {
$crate::shader!(rin::gl::FRAGMENT_SHADER, $path, $replacements)
};
($path: expr) => {
$crate::shader!(rin::gl::FRAGMENT_SHADER, $path)
};
}
#[macro_export]
macro_rules! shader_source {
($ty: expr, $source: expr) => {{
let include_name = match $ty{
gl::VERTEX_SHADER => format!("vertex shader inlined in {}:{}:{}", file!(), line!(), column!()),
gl::FRAGMENT_SHADER => format!("fragment_shader inlined in {}:{}:{}", file!(), line!(), column!()),
_ => panic!("Shader type not supported yet"),
};
$crate::renderer::Shader::Source{
include_name,
source: $source.to_owned(),
replacements: vec![],
base_path: None,
includes: Vec::new(),
ty: $ty,
}
}};
}
#[macro_export]
macro_rules! vertex_shader_source {
($source: expr) => {
$crate::shader_source!(rin::gl::VERTEX_SHADER, $source)
};
}
#[macro_export]
macro_rules! fragment_shader_source {
($source: expr) => {
$crate::shader_source!(rin::gl::FRAGMENT_SHADER, $source)
};
}
#[derive(Material)]
pub struct ShaderMaterial{
#[material(skip)]
shaders: Vec<Shader>,
#[material(skip)]
uniforms_fn: Option<RefCell<Box<dyn FnMut() -> PropertyChanged<Vec<glin::program::Uniform>>>>>,
#[material(skip)]
uniforms: Parameter<Vec<glin::program::Uniform>>,
#[material(skip)]
data_fn: Option<RefCell<Box<dyn FnMut() -> PropertyChanged<Option<Data>>>>>,
#[material(skip)]
data: Parameter<Option<Data>>,
properties: Parameter<Vec<Property>>,
alpha_type: Parameter<AlphaType>,
#[material(skip)]
priority: Option<i32>,
#[material(skip)]
textures: Parameter<Vec<(String, TextureSampler)>>,
#[material(skip)]
defines: Vec<(String, String)>,
}
pub struct ShaderMaterialBuilder{
shaders: Vec<Shader>,
uniforms_fn: Option<RefCell<Box<dyn FnMut() -> PropertyChanged<Vec<glin::program::Uniform>>>>>,
uniforms: Parameter<Vec<glin::program::Uniform>>,
data_fn: Option<RefCell<Box<dyn FnMut() -> PropertyChanged<Option<Data>>>>>,
data: Parameter<Option<Data>>,
properties: Vec<Property>,
alpha_type: AlphaType,
priority: Option<i32>,
textures: Vec<(String, TextureSampler)>,
defines: Vec<(String, String)>,
}
impl ShaderMaterialBuilder{
pub fn new() -> ShaderMaterialBuilder {
ShaderMaterialBuilder {
shaders: vec![],
properties: vec![],
uniforms_fn: None,
uniforms: Parameter::new(vec![]),
data: Parameter::new(None),
data_fn: None,
alpha_type:AlphaType::None,
priority: None,
textures: vec![],
defines: vec![],
}
}
pub fn shader(mut self, shader: Shader) -> ShaderMaterialBuilder{
self.shaders.push(shader);
self
}
pub fn uniforms_fn<F>(mut self, uniforms: F) -> ShaderMaterialBuilder
where F: FnMut() -> PropertyChanged<Vec<glin::program::Uniform>> + 'static
{
self.uniforms_fn = Some(RefCell::new(Box::new(uniforms)));
self
}
pub fn uniforms(mut self, uniforms: Vec<glin::program::Uniform>) -> ShaderMaterialBuilder {
self.uniforms.set(uniforms);
self
}
pub fn data_fn<F>(mut self, data: F) -> ShaderMaterialBuilder
where F: FnMut() -> PropertyChanged<Option<Data>> + 'static
{
self.data_fn = Some(RefCell::new(Box::new(data)));
self
}
pub fn data(mut self, data: Data) -> ShaderMaterialBuilder {
self.data.set(Some(data));
self
}
pub fn property(mut self, property: Property) -> ShaderMaterialBuilder{
self.properties.push(property);
self
}
pub fn alpha_type(mut self, alpha_type: AlphaType) -> ShaderMaterialBuilder{
self.alpha_type = alpha_type;
self
}
pub fn priority(mut self, priority: i32) -> ShaderMaterialBuilder{
self.priority = Some(priority);
self
}
pub fn texture(mut self, uniform_name: String, texture: TextureRef) -> ShaderMaterialBuilder{
self.textures.push((uniform_name, TextureSampler::from(texture)));
self
}
pub fn texture_sampler(mut self, uniform_name: String, texture: TextureSampler) -> ShaderMaterialBuilder{
self.textures.push((uniform_name, texture));
self
}
pub fn define<S1: Into<String>, S2: Into<String>>(mut self, key: S1, value: S2) -> ShaderMaterialBuilder {
self.defines.push((key.into(), value.into()));
self
}
pub fn debug_textoords(mut self) -> ShaderMaterialBuilder {
self.defines.push(("DEBUG_TEXCOORDS".into(), "1".into()));
self
}
pub fn debug_normals(mut self) -> ShaderMaterialBuilder {
self.defines.push(("DEBUG_NORMALS".into(), "1".into()));
self
}
pub fn build(self) -> ShaderMaterial {
ShaderMaterial{
shaders: self.shaders,
uniforms: self.uniforms,
uniforms_fn: self.uniforms_fn,
data: self.data,
data_fn: self.data_fn,
properties: Parameter::new(self.properties),
alpha_type: Parameter::new(self.alpha_type),
priority: self.priority,
textures: Parameter::new(self.textures),
defines: self.defines,
}
}
}
impl ShaderMaterial {
pub fn set_uniforms(&mut self, uniforms: Vec<glin::program::Uniform>) {
self.uniforms.set(uniforms)
}
pub fn set_data(&mut self, data: Data) {
self.data.set(Some(data))
}
}
impl Material for ShaderMaterial{
fn shaders(&self) -> PropertyChanged<Vec<Shader>>{
PropertyChanged::Always(self.shaders.clone())
}
fn uniforms(&self) -> PropertyChanged<Vec<glin::program::Uniform>>{
match &self.uniforms_fn{
None => if self.uniforms.has_changed() {
PropertyChanged::New(self.uniforms.get().clone())
}else{
PropertyChanged::Old
},
Some(f) => {
let f = &mut *f.borrow_mut();
f()
}
}
}
fn data(&self) -> PropertyChanged<Option<Data>>{
match &self.data_fn{
None => {
if self.data.has_changed() {
PropertyChanged::New(self.data.get().clone())
}else{
PropertyChanged::Old
}
},
Some(f) => {
let f = &mut *f.borrow_mut();
f()
}
}
}
fn textures(&self) -> PropertyChanged<Vec<(&str, TextureSampler)>>{
if self.textures.has_changed() {
let textures = self.textures.iter()
.map(|(name, tex)| (name.as_str(), tex.clone()))
.collect();
PropertyChanged::New(textures)
}else{
PropertyChanged::Old
}
}
fn transparency(&self) -> PropertyChanged<MaterialTransparency>{
if self.alpha_type.has_changed() {
PropertyChanged::New(MaterialTransparency{
alpha_type: *self.alpha_type,
is_translucent: *self.alpha_type != AlphaType::None,
is_visible: true,
priority: self.priority,
})
}else{
PropertyChanged::Old
}
}
fn program_settings(&self) -> PropertyChanged<ProgramSettings> {
PropertyChanged::Always(ProgramSettings{
defines: self.defines.clone(),
.. Default::default()
})
}
}