use glin;
use super::{ShadowMap, CreationProxy, Light};
use gl;
#[cfg(feature="dds")]
use std::path::Path;
#[cfg(feature="dds")]
use util::{Result, Error};
use glin::CreationContext;
#[cfg(feature="dds")]
use graphics::dds::Dds;
pub struct ImageBasedLight{
diffuse: glin::CubeMap,
specular: glin::CubeMap,
strength: f32,
}
pub struct Builder{
pub(crate) gl: CreationProxy
}
impl Builder {
#[cfg(feature="dds")]
pub fn from_paths<P: AsRef<Path>>(&self, diffuse: P, specular: P) -> Result<ImageBasedLight>{
let diffuse_img = Dds::load(diffuse)
.map_err(|e| Error::with_cause("Error loading diffuse map", e))?;
let diffuse = self.gl.new_cubemap().from_cubemap_image(&diffuse_img)
.map_err(|e| Error::with_cause("Error loading diffuse map texture", e))?;
let specular_img = Dds::load(specular)
.map_err(|e| Error::with_cause("Error loading specular map", e))?;
let specular = self.gl.new_cubemap().from_cubemap_image(&specular_img)
.map_err(|e| Error::with_cause("Error loading specular map texture", e))?;
Ok(ImageBasedLight::new(diffuse, specular))
}
pub fn from_cubemaps(mut diffuse: glin::CubeMap, mut specular: glin::CubeMap) -> ImageBasedLight{
diffuse.set_min_mag_filters(glin::gl::LINEAR, glin::gl::LINEAR);
specular.set_min_mag_filters(glin::gl::LINEAR_MIPMAP_LINEAR, glin::gl::LINEAR);
ImageBasedLight{
diffuse,
specular,
strength: 1.,
}
}
}
impl ImageBasedLight{
pub fn new(diffuse: glin::CubeMap, specular: glin::CubeMap) -> ImageBasedLight{
ImageBasedLight{
diffuse,
specular,
strength: 1.,
}
}
pub fn diffuse(&self) -> &glin::CubeMap{
&self.diffuse
}
pub fn specular(&self) -> &glin::CubeMap{
&self.specular
}
pub fn strength(&self) -> f32{
self.strength
}
pub fn set_diffuse(&mut self, diffuse: glin::CubeMap){
self.diffuse = diffuse;
}
pub fn set_specular(&mut self, specular: glin::CubeMap){
self.specular = specular;
}
pub fn set_strength(&mut self, strength: f32){
self.strength = strength;
}
}
impl Light for ImageBasedLight{
fn ty(&self) -> &str{
"IMAGE_BASED_LIGHT"
}
fn uniforms(&self, _shadow_map_idx_offset: &mut usize) -> Vec<glin::program::Uniform>{
uniforms!{
enabled: 1f32,
type: 4f32,
diffmap: (&self.diffuse, gl::TextureBindingPoints::DiffuseIbl as u32),
envmap: (&self.specular, gl::TextureBindingPoints::SpecularIbl as u32),
ibl_strength: self.strength,
}
}
fn shadow_maps(&self) -> Vec<&dyn ShadowMap>{
vec![]
}
}
#[cfg(feature="dds")]
#[doc(inline)]
pub use self::generate_dds::*;
#[cfg(feature="dds")]
mod generate_dds{
use glin;
use graphics;
use gl::{Renderer2d, ShaderMaterial, Renderer};
use color::consts::BLACK;
use graphics::dds::{self, Dds};
use std::mem;
use std::slice;
use util::LogErr;
use glin::{gl, gl::types::*};
#[cfg(feature="gl")]
fn fbo_format_to_dds(format: glin::fbo::ColorFormat) -> dds::Format{
match format{
glin::fbo::ColorFormat::R8 |
glin::fbo::ColorFormat::R16 |
glin::fbo::ColorFormat::R32F => dds::Format::Gray,
glin::fbo::ColorFormat::RG8 |
glin::fbo::ColorFormat::RG16 |
glin::fbo::ColorFormat::RG32F => unimplemented!(),
glin::fbo::ColorFormat::RGB8 |
glin::fbo::ColorFormat::RGB16 |
glin::fbo::ColorFormat::RGB16F |
glin::fbo::ColorFormat::RGB32F => dds::Format::RGB,
glin::fbo::ColorFormat::RGBA8 |
glin::fbo::ColorFormat::RGBA16 |
glin::fbo::ColorFormat::RGBA16F |
glin::fbo::ColorFormat::RGBA32F => dds::Format::RGBA,
}
}
#[cfg(any(feature="gles", feature="webgl"))]
fn fbo_format_to_dds(format: glin::fbo::ColorFormat) -> dds::Format{
match format{
glin::fbo::ColorFormat::R8 |
glin::fbo::ColorFormat::R32F => dds::Format::Gray,
glin::fbo::ColorFormat::RG8 |
glin::fbo::ColorFormat::RG32F => unimplemented!(),
glin::fbo::ColorFormat::RGB8 |
glin::fbo::ColorFormat::RGB16F |
glin::fbo::ColorFormat::RGB32F => dds::Format::RGB,
glin::fbo::ColorFormat::RGBA8 |
glin::fbo::ColorFormat::RGBA16F |
glin::fbo::ColorFormat::RGBA32F => dds::Format::RGBA,
}
}
pub fn generate_radiance_map_from_faces(env_images: &glin::cubemap::Faces<graphics::Image>, format: glin::fbo::ColorFormat, gl: &Renderer) -> Dds {
let envmap = gl.new_cubemap().from_faces(env_images).unwrap();
generate_radiance_map(&envmap, format, gl)
}
pub fn generate_radiance_map_from_cubemap_img(env_image: &graphics::Dds, format: glin::fbo::ColorFormat, gl: &Renderer) -> Dds {
let envmap = gl.new_cubemap().from_cubemap_image(env_image).unwrap();
generate_radiance_map(&envmap, format, gl)
}
pub fn generate_radiance_map(envmap: &glin::CubeMap, format: glin::fbo::ColorFormat, gl: &Renderer) -> Dds {
let w = envmap.width();
let h = w;
let program = shaders::get_radiance_program(gl);
let num_mips = (w as f32).log2().floor() as i32 + 1;
let uniforms = uniforms!{
maximumMips: num_mips,
cubeSize: envmap.width() as f32,
cubeMap: (envmap, 0)
};
let mut material = ShaderMaterial::new(program);
#[cfg(feature="gl")]
material.set_properties(vec![
glin::Property::TextureCubemapSeamless(true),
]);
let mut dds_data = vec![ ];
let mut fbos = (0..num_mips).map(|mip|{
let w = w as i32 >> mip;
let h = h as i32 >> mip;
let color = gl.new_fbo_color_attachment()
.texture(w as u32, h as u32, format)
.unwrap();
gl.new_fbo().from_color_no_depth(color).unwrap()
}).collect::<Vec<_>>();
let gl_format = glin::gl_format_from_internal(format as GLenum).unwrap();
let gl_type = glin::gl_type_from_internal(format as GLenum).unwrap();
for f in 0..6 {
let mut uniforms = uniforms.clone();
uniforms.push(glin::program::uniform("face", &(f as i32)));
for mip in 0..num_mips as i32 {
let mut uniforms = uniforms.clone();
uniforms.push(glin::program::uniform("currentMip", &mip));
material.set_uniforms(uniforms);
let fbo = &mut fbos[mip as usize];
{
let gl = gl.with_fbo(fbo);
gl.clear(&BLACK);
gl.draw_mesh_with_material(&graphics::rectangle_texcoords(-1., -1., 2., 2., 0., 0., 1., 1.), &material);
}
dds_data.extend(download_fbo(fbo, gl_format, gl_type));
}
}
let dds_format = fbo_format_to_dds(format);
dds::Builder::new(w as usize, h as usize, dds_format, dds::Type::Float)
.is_cubemap_allfaces()
.has_mipmaps(num_mips as usize)
.create(dds_data)
.unwrap()
}
pub fn generate_irradiance_map_from_faces(env_images: &glin::cubemap::Faces<graphics::Image>, size: u32, format: glin::fbo::ColorFormat, gl: &Renderer) -> graphics::Dds {
let envmap = gl.new_cubemap().from_faces(env_images).unwrap();
generate_irradiance_map(&envmap, size, format, gl)
}
pub fn generate_irradiance_map_from_cubemap_img(env_image: &Dds, size: u32, format: glin::fbo::ColorFormat, gl: &Renderer) -> Dds {
let envmap = gl.new_cubemap().from_cubemap_image(env_image).unwrap();
generate_irradiance_map(&envmap, size, format, gl)
}
pub fn generate_irradiance_map(envmap: &glin::CubeMap, size: u32, format: glin::fbo::ColorFormat, gl: &Renderer) -> Dds {
let w = size;
let h = size;
let program = shaders::get_irradiance_program(gl);
let color = gl.new_fbo_color_attachment()
.texture(w, h, format)
.unwrap();
let mut fbo = gl.new_fbo().from_color_no_depth(color).unwrap();
let mut dds_data = vec![ ];
let uniforms = uniforms!{
cubeSize: envmap.width() as f32,
cubeMap: (envmap, 0)
};
let mut material = ShaderMaterial::new(program);
#[cfg(feature="gl")]
material.set_properties(vec![
glin::Property::TextureCubemapSeamless(true),
]);
let gl_format = glin::gl_format_from_internal(format as GLenum).unwrap();
let gl_type = glin::gl_type_from_internal(format as GLenum).unwrap();
for f in 0..6i32 {
let mut uniforms = uniforms.clone();
uniforms.push(glin::program::uniform("face", &f));
material.set_uniforms(uniforms);
gl.with_fbo(&mut fbo)
.draw_mesh_with_material(&graphics::rectangle_texcoords(-1., -1., 2., 2., 0., 0., 1., 1.), &material);
dds_data.extend(download_fbo(&fbo, gl_format, gl_type));
}
let dds_format = fbo_format_to_dds(format);
dds::Builder::new(w as usize, h as usize, dds_format, dds::Type::Float)
.is_cubemap_allfaces()
.create(dds_data)
.unwrap()
}
pub fn equirectangular_to_dds(map: &glin::Texture, size: u32, format: glin::fbo::ColorFormat, gl: &Renderer) -> Dds{
let w = size;
let h = size;
let program = shaders::get_equirectangular_program(gl);
let color = gl.new_fbo_color_attachment()
.texture(w, h, format)
.unwrap();
let mut fbo = gl.new_fbo().from_color_no_depth(color).unwrap();
let mut dds_data = vec![ ];
let mut material = ShaderMaterial::new(program);
#[cfg(feature="gl")]
material.set_properties(vec![
glin::Property::TextureCubemapSeamless(true),
]);
let gl_format = glin::gl_format_from_internal(format as GLenum).unwrap();
let gl_type = glin::gl_type_from_internal(format as GLenum).unwrap();
for f in 0..6i32 {
let uniforms = uniforms!{
face: f,
equirectangular_map: map,
};
material.set_uniforms(uniforms);
gl.with_fbo(&mut fbo)
.draw_mesh_with_material(&graphics::rectangle_texcoords(-1., -1., 2., 2., 0., 1., 1., 0.), &material);
dds_data.extend(download_fbo(&fbo, gl_format, gl_type));
}
let dds_format = fbo_format_to_dds(format);
dds::Builder::new(w as usize, h as usize, dds_format, dds::Type::Float)
.is_cubemap_allfaces()
.create(dds_data)
.log_err("Error creating dds")
.unwrap()
}
mod shaders{
use glin;
use gl;
program_cache!("shaders/envgen.vs.glsl", "shaders/irradiance.fs.glsl", get_irradiance_program, IRR_SHADER);
program_cache!("shaders/envgen.vs.glsl", "shaders/radiance.fs.glsl", get_radiance_program, RAD_SHADER);
program_cache!(glin::program::Settings{
version: gl::default_glsl_version(),
precission: glin::program::ShaderPrecision::High,
extensions: vec![],
defines: vec![],
shaders: vec![
(glin::gl::VERTEX_SHADER, include_str!("shaders/envgen.vs.glsl")),
(glin::gl::FRAGMENT_SHADER, include_str!("shaders/equirectangular.fs.glsl")),
],
bindings: gl::default_attribute_bindings(),
.. Default::default()
}, get_equirectangular_program, EQUI_SHADER);
}
#[cfg(feature="gl")]
unsafe fn read_fbo<T>(fbo: &glin::Fbo, buffer: &mut [T], format: GLenum, ty: GLenum) {
fbo.color_tex(0).unwrap().read_to(buffer, format, ty);
}
#[cfg(feature="webgl")]
unsafe fn read_fbo<T>(fbo: &glin::Fbo, buffer: &mut [T], format: GLenum, ty: GLenum)
where for <'s> &'s mut [T]: gl::AsArrayBufferView<'s>
{
fbo.read_to(0, 0, fbo.width() as i32, fbo.height() as i32, format, ty, buffer);
}
#[cfg(feature="gles")]
unsafe fn read_fbo<T>(fbo: &glin::Fbo, buffer: &mut [T], format: GLenum, ty: GLenum)
{
fbo.read_to(0, 0, fbo.width() as i32, fbo.height() as i32, format, ty, buffer);
}
#[cfg(feature="freeimage")]
fn download_fbo(fbo: &glin::Fbo, format: GLenum, ty: GLenum) -> Vec<u8> {
let (img_ty, bpp) = match ty {
gl::UNSIGNED_BYTE => match format{
gl::RED => (graphics::image::Type::BITMAP, 8 * 1),
gl::RG => (graphics::image::Type::BITMAP, 8 * 2),
gl::RGB => (graphics::image::Type::BITMAP, 8 * 3),
gl::RGBA => (graphics::image::Type::BITMAP, 8 * 4),
_ => unimplemented!(),
}
gl::UNSIGNED_SHORT => match format{
gl::RGB => (graphics::image::Type::RGB16, 16 * 3),
gl::RGBA => (graphics::image::Type::RGBA16, 16 * 4),
_ => unimplemented!(),
}
gl::HALF_FLOAT | gl::FLOAT => match format{
gl::RGB => (graphics::image::Type::RGBF, 32 * 3),
gl::RGBA => (graphics::image::Type::RGBAF, 32 * 4),
_ => unimplemented!(),
}
_=> unimplemented!()
};
let mut img = graphics::Image::new::<u8>(img_ty,
fbo.width() as usize, fbo.height() as usize, bpp, None);
unsafe{ read_fbo(fbo, img.pixels_mut::<u8>(), format, ty); }
img.flip_vertical().unwrap().bits().to_vec()
}
#[cfg(feature="image")]
fn raw_data<T>(img: T) -> Vec<u8>
where T: graphics::image::GenericImageView + 'static,
<T as graphics::image::GenericImageView>::Pixel: 'static,
<<T as graphics::image::GenericImageView>::Pixel as graphics::image::Pixel>::Subpixel: 'static
{
let raw = graphics::image::imageops::flip_vertical(&img)
.into_raw();
unsafe{
slice::from_raw_parts(raw.as_ptr() as *const u8, raw.len() * mem::size_of::<<<T as graphics::image::GenericImageView>::Pixel as graphics::image::Pixel>::Subpixel>())
.to_vec()
}
}
#[cfg(feature="image")]
#[cfg(feature="webgl")]
unsafe fn download_to_img<T: graphics::image::Primitive + 'static>(fbo: &glin::Fbo, format: GLenum, ty: GLenum) -> Vec<u8>
where for <'s> &'s mut [T]: gl::AsArrayBufferView<'s> {
match format{
gl::RED => {
let mut buffer: Vec<T> = vec![mem::uninitialized(); (fbo.width() * fbo.height()) as usize];
read_fbo(fbo, &mut buffer, format, ty);
let img: graphics::image::ImageBuffer<graphics::image::Luma<T>, Vec<T>> =
graphics::image::ImageBuffer::from_raw(fbo.width(), fbo.height(), buffer).unwrap();
raw_data(img)
}
gl::RG => {
let mut buffer: Vec<T> = vec![mem::uninitialized(); (fbo.width() * fbo.height() * 2) as usize];
read_fbo(fbo, &mut buffer, format, ty);
let img: graphics::image::ImageBuffer<graphics::image::LumaA<T>, Vec<T>> =
graphics::image::ImageBuffer::from_raw(fbo.width(), fbo.height(), buffer).unwrap();
raw_data(img)
}
gl::RGB => {
let mut buffer: Vec<T> = vec![mem::uninitialized(); (fbo.width() * fbo.height() * 3) as usize];
read_fbo(fbo, &mut buffer, format, ty);
let img: graphics::image::ImageBuffer<graphics::image::Rgb<T>, Vec<T>> =
graphics::image::ImageBuffer::from_raw(fbo.width(), fbo.height(), buffer).unwrap();
raw_data(img)
}
gl::RGBA => {
let mut buffer: Vec<T> = vec![mem::uninitialized(); (fbo.width() * fbo.height() * 4) as usize];
read_fbo(fbo, &mut buffer, format, ty);
let img: graphics::image::ImageBuffer<graphics::image::Rgba<T>, Vec<T>> =
graphics::image::ImageBuffer::from_raw(fbo.width(), fbo.height(), buffer).unwrap();
raw_data(img)
}
_ => unimplemented!()
}
}
#[cfg(feature="image")]
#[cfg(any(feature="gl", feature="gles"))]
unsafe fn download_to_img<T: graphics::image::Primitive + 'static>(fbo: &glin::Fbo, format: GLenum, ty: GLenum) -> Vec<u8> {
match format{
gl::RED => {
let mut buffer: Vec<T> = vec![mem::uninitialized(); (fbo.width() * fbo.height()) as usize];
read_fbo(fbo, &mut buffer, format, ty);
let img: graphics::image::ImageBuffer<graphics::image::Luma<T>, Vec<T>> =
graphics::image::ImageBuffer::from_raw(fbo.width(), fbo.height(), buffer).unwrap();
raw_data(img)
}
gl::RG => {
let mut buffer: Vec<T> = vec![mem::uninitialized(); (fbo.width() * fbo.height() * 2) as usize];
read_fbo(fbo, &mut buffer, format, ty);
let img: graphics::image::ImageBuffer<graphics::image::LumaA<T>, Vec<T>> =
graphics::image::ImageBuffer::from_raw(fbo.width(), fbo.height(), buffer).unwrap();
raw_data(img)
}
gl::RGB => {
let mut buffer: Vec<T> = vec![mem::uninitialized(); (fbo.width() * fbo.height() * 3) as usize];
read_fbo(fbo, &mut buffer, format, ty);
let img: graphics::image::ImageBuffer<graphics::image::Rgb<T>, Vec<T>> =
graphics::image::ImageBuffer::from_raw(fbo.width(), fbo.height(), buffer).unwrap();
raw_data(img)
}
gl::RGBA => {
let mut buffer: Vec<T> = vec![mem::uninitialized(); (fbo.width() * fbo.height() * 4) as usize];
read_fbo(fbo, &mut buffer, format, ty);
let img: graphics::image::ImageBuffer<graphics::image::Rgba<T>, Vec<T>> =
graphics::image::ImageBuffer::from_raw(fbo.width(), fbo.height(), buffer).unwrap();
raw_data(img)
}
_ => unimplemented!()
}
}
#[cfg(feature="image")]
fn download_fbo(fbo: &glin::Fbo, format: GLenum, ty: GLenum) -> Vec<u8> {
unsafe{
match ty {
gl::UNSIGNED_BYTE => download_to_img::<u8>(fbo, format, ty),
gl::UNSIGNED_SHORT => download_to_img::<u16>(fbo, format, ty),
gl::HALF_FLOAT => download_to_img::<f32>(fbo, format, gl::FLOAT),
gl::FLOAT => download_to_img::<f32>(fbo, format, ty),
_ => unimplemented!()
}
}
}
}
#[doc(inline)]
pub use self::generate::*;
mod generate{
use glin;
use graphics;
use glin::{gl, gl::types::*};
use color::consts::BLACK;
use std::borrow::Borrow;
use gl::{Renderer2d, ShaderMaterial, Renderer};
pub fn cubemap_to_equirectangular(cubemap: &glin::CubeMap, w: u32, h: u32, color_format: glin::fbo::ColorFormat, gl: &Renderer) -> glin::Texture{
cubemap_level_to_equirectangular(cubemap, w, h, 0, color_format, gl)
}
pub fn cubemap_level_to_equirectangular(cubemap: &glin::CubeMap, w: u32, h: u32, level: u32, color_format: glin::fbo::ColorFormat, gl: &Renderer) -> glin::Texture{
let program = shaders::get_to_equirectangular_program(gl);
let color = gl.new_fbo_color_attachment()
.texture(w, h, color_format)
.unwrap();
let mut fbo = gl.new_fbo().from_color_no_depth(color).unwrap();
let mut material = ShaderMaterial::new(program);
#[cfg(feature="gl")]
material.set_properties(vec![
glin::Property::TextureCubemapSeamless(true),
]);
{
let uniforms = uniforms!{
cubemap: cubemap,
level: level as i32,
};
material.set_uniforms(uniforms);
gl.with_fbo(&mut fbo)
.draw_mesh_with_material(&graphics::rectangle_texcoords(-1., -1., 2., 2., 0., 0., 1., 1.), &material);
}
let (color, _depth) = fbo.into_attachments();
if let glin::fbo::ColorAttachment::Texture(tex) = color.into_iter().next().unwrap() {
tex
}else{
unreachable!()
}
}
pub fn equirectangular_to_cubemap(map: &glin::Texture, size: u32, color_format: glin::fbo::ColorFormat, gl: &Renderer) -> glin::CubeMap{
let w = size;
let h = size;
let program = shaders::get_equirectangular_program(gl);
let cubemap = gl.new_cubemap().from_format(glin::cubemap::Format{
internal_format: color_format as GLenum,
width: w,
height: h,
levels: 1,
}).unwrap();
let mut material = ShaderMaterial::new(program);
#[cfg(feature="gl")]
material.set_properties(vec![
glin::Property::TextureCubemapSeamless(true),
]);
for f in 0..6 {
let uniforms = uniforms!{
face: f as i32,
equirectangular_map: map,
};
material.set_uniforms(uniforms);
let fbo = gl.new_fbo()
.from_cubemap_face_no_depth(&cubemap, gl::TEXTURE_CUBE_MAP_POSITIVE_X + f as u32)
.unwrap();
gl.with_fbo(&fbo)
.draw_mesh_with_material(&graphics::rectangle_texcoords(-1., -1., 2., 2., 0., 0., 1., 1.), &material);
}
cubemap
}
pub fn equirectangular_to_cubemap_allocate_levels(map: &glin::Texture, size: u32, color_format: glin::fbo::ColorFormat, gl: &Renderer) -> glin::CubeMap{
let w = size;
let h = size;
let program = shaders::get_equirectangular_program(gl);
let cubemap = gl.new_cubemap().from_format(glin::cubemap::Format{
internal_format: color_format as GLenum,
width: w,
height: h,
levels: (w as f32).log2().floor() as u32 + 1,
}).unwrap();
let mut material = ShaderMaterial::new(program);
#[cfg(feature="gl")]
material.set_properties(vec![
glin::Property::TextureCubemapSeamless(true),
]);
for f in 0..6 {
let uniforms = uniforms!{
face: f as i32,
equirectangular_map: map,
};
material.set_uniforms(uniforms);
let fbo = gl.new_fbo()
.from_cubemap_face_no_depth(&cubemap, gl::TEXTURE_CUBE_MAP_POSITIVE_X + f as u32)
.unwrap();
gl.with_fbo(&fbo)
.draw_mesh_with_material(&graphics::rectangle_texcoords(-1., -1., 2., 2., 0., 0., 1., 1.), &material);
}
cubemap
}
pub fn equirectangular_levels_to_cubemap<'a, T: Borrow<glin::Texture>, I: IntoIterator<Item = T>>(levels: I, size: u32, color_format: glin::fbo::ColorFormat, gl: &Renderer) -> glin::CubeMap{
let w = size;
let h = size;
let program = shaders::get_equirectangular_program(gl);
let cubemap = gl.new_cubemap().from_format(glin::cubemap::Format{
internal_format: color_format as GLenum,
width: w,
height: h,
levels: (w as f32).log2().floor() as u32 + 1,
}).unwrap();
let mut material = ShaderMaterial::new(program);
#[cfg(feature="gl")]
material.set_properties(vec![
glin::Property::TextureCubemapSeamless(true),
]);
for (level, map) in levels.into_iter().enumerate(){
for f in 0..6 {
let uniforms = uniforms!{
face: f as i32,
equirectangular_map: map.borrow(),
};
material.set_uniforms(uniforms);
let fbo = gl.new_fbo()
.from_cubemap_face_level_no_depth(&cubemap, gl::TEXTURE_CUBE_MAP_POSITIVE_X + f as u32, level as u32)
.unwrap();
gl.with_fbo(&fbo)
.draw_mesh_with_material(&graphics::rectangle_texcoords(-1., -1., 2., 2., 0., 0., 1., 1.), &material);
}
}
cubemap
}
pub fn generate_brdf_lut(size: u32, color_format: glin::fbo::ColorFormat, gl: &Renderer) -> glin::Texture {
let w = size;
let h = size;
let program = shaders::get_brdf_lut_program(gl);
let color = gl.new_fbo_color_attachment()
.texture(w, h, color_format)
.unwrap();
let mut fbo = gl.new_fbo().from_color_no_depth(color).unwrap();
{
let gl = gl.with_fbo(&mut fbo);
gl.clear(&BLACK);
gl.draw_mesh_with_material(&graphics::rectangle_texcoords(-1., -1., 2., 2., 0., 0., 1., 1.), &program);
}
if let Some(glin::fbo::ColorAttachment::Texture(tex)) = fbo.into_attachments().0.pop(){
tex
}else{
unimplemented!()
}
}
pub fn generate_cloth_ashikhmin_brdf_lut(size: u32, color_format: glin::fbo::ColorFormat, gl: &Renderer) -> glin::Texture {
let w = size;
let h = size;
let program = shaders::get_cloth_ashikhmin_brdf_lut_program(gl);
let color = gl.new_fbo_color_attachment()
.texture(w, h, color_format)
.unwrap();
let mut fbo = gl.new_fbo().from_color_no_depth(color).unwrap();
{
let gl = gl.with_fbo(&mut fbo);
gl.clear(&BLACK);
gl.draw_mesh_with_material(&graphics::rectangle_texcoords(-1., -1., 2., 2., 0., 0., 1., 1.), &program);
}
if let Some(glin::fbo::ColorAttachment::Texture(tex)) = fbo.into_attachments().0.pop(){
tex
}else{
unimplemented!()
}
}
pub fn generate_cloth_charlie_brdf_lut(size: u32, color_format: glin::fbo::ColorFormat, gl: &Renderer) -> glin::Texture {
let w = size;
let h = size;
let program = shaders::get_cloth_charlie_brdf_lut_program(gl);
let color = gl.new_fbo_color_attachment()
.texture(w, h, color_format)
.unwrap();
let mut fbo = gl.new_fbo().from_color_no_depth(color).unwrap();
{
let gl = gl.with_fbo(&mut fbo);
gl.clear(&BLACK);
gl.draw_mesh_with_material(&graphics::rectangle_texcoords(-1., -1., 2., 2., 0., 0., 1., 1.), &program);
}
if let Some(glin::fbo::ColorAttachment::Texture(tex)) = fbo.into_attachments().0.pop(){
tex
}else{
unimplemented!()
}
}
pub fn generate_irradiance_cubemap(envmap: &glin::CubeMap, size: u32, color_format: glin::fbo::ColorFormat, gl: &Renderer) -> glin::CubeMap {
let w = size;
let h = size;
let program = shaders::get_irradiance_program(gl);
let cubemap = gl.new_cubemap().from_format(glin::cubemap::Format{
internal_format: color_format as GLenum,
width: w,
height: h,
levels: 1,
}).unwrap();
let uniforms = uniforms!{
cubeSize: envmap.width() as f32,
cubeMap: (envmap, 0)
};
let mut material = ShaderMaterial::new(program);
#[cfg(features="gl")]
material.set_properties(vec![
glin::Property::TextureCubemapSeamless(true),
]);
for f in 0..6i32 {
let mut uniforms = uniforms.clone();
uniforms.push(glin::program::uniform("face", &f));
material.set_uniforms(uniforms);
let fbo = gl.new_fbo()
.from_cubemap_face_no_depth(&cubemap, gl::TEXTURE_CUBE_MAP_POSITIVE_X + f as u32)
.unwrap();
gl.with_fbo(&fbo)
.draw_mesh_with_material(&graphics::rectangle_texcoords(-1., -1., 2., 2., 0., 1., 1., 0.), &material);
}
cubemap
}
pub fn generate_radiance_cubemap(envmap: &glin::CubeMap, color_format: glin::fbo::ColorFormat, gl: &Renderer) -> glin::CubeMap {
let w = envmap.width();
let h = w;
let program = shaders::get_radiance_program(gl);
let num_mips = (w as f32).log2().floor() as i32 + 1;
let uniforms = uniforms!{
maximumMips: num_mips,
cubeSize: envmap.width() as f32,
cubeMap: (envmap, 0)
};
let mut material = ShaderMaterial::new(program);
#[cfg(features="gl")]
material.set_properties(vec![
glin::Property::TextureCubemapSeamless(true),
]);
let cubemap = gl.new_cubemap().from_format(glin::cubemap::Format{
internal_format: color_format as GLenum,
width: w,
height: h,
levels: num_mips as u32,
}).unwrap();
for f in 0..6 {
let mut uniforms = uniforms.clone();
uniforms.push(glin::program::uniform("face", &(f as i32)));
for mip in 0..num_mips as i32 {
let mut uniforms = uniforms.clone();
uniforms.push(glin::program::uniform("currentMip", &mip));
material.set_uniforms(uniforms);
let fbo = gl.new_fbo()
.from_cubemap_face_level_no_depth(&cubemap, gl::TEXTURE_CUBE_MAP_POSITIVE_X + f, mip as u32)
.unwrap();
let gl = gl.with_fbo(&fbo);
let gl = gl.with_properties(&[glin::Property::Viewport(fbo.viewport())]);
gl.clear(&BLACK);
gl.draw_mesh_with_material(&graphics::rectangle_texcoords(-1., -1., 2., 2., 0., 1., 1., 0.), &material);
}
}
cubemap
}
mod shaders{
use glin;
use gl;
program_cache!(glin::program::Settings{
version: gl::default_glsl_version(),
precission: glin::program::ShaderPrecision::High,
extensions: vec![],
defines: vec![],
shaders: vec![
(glin::gl::VERTEX_SHADER, include_str!("shaders/envgen.vs.glsl")),
(glin::gl::FRAGMENT_SHADER, include_str!("shaders/equirectangular.fs.glsl")),
],
bindings: gl::default_attribute_bindings(),
.. Default::default()
}, get_equirectangular_program, EQUI_SHADER);
program_cache!(glin::program::Settings{
version: gl::default_glsl_version(),
precission: glin::program::ShaderPrecision::High,
extensions: vec![],
defines: vec![],
shaders: vec![
(glin::gl::VERTEX_SHADER, include_str!("shaders/envgen.vs.glsl")),
(glin::gl::FRAGMENT_SHADER, include_str!("shaders/to_equirectangular.fs.glsl")),
],
bindings: gl::default_attribute_bindings(),
.. Default::default()
}, get_to_equirectangular_program, TO_EQUI_SHADER);
program_cache!(glin::program::Settings{
version: ::gl::default_glsl_version(),
extensions: vec![],
precission: glin::program::ShaderPrecision::High,
defines: vec![("MATERIAL_TYPE", "STANDARD_MATERIAL")],
shaders: vec![
(glin::gl::VERTEX_SHADER, include_str!("shaders/envgen.vs.glsl")),
(glin::gl::FRAGMENT_SHADER, include_str!("shaders/brdf_lut.fs.glsl")),
],
bindings: ::gl::default_attribute_bindings(),
.. Default::default()
}, get_brdf_lut_program, LUT_SHADER);
program_cache!(glin::program::Settings{
version: ::gl::default_glsl_version(),
extensions: vec![],
precission: glin::program::ShaderPrecision::High,
defines: vec![
("MATERIAL_TYPE", "CLOTH_MATERIAL"),
("BRDF_CLOTH_D", "SPECULAR_D_ASHIKHMIN"),
],
shaders: vec![
(glin::gl::VERTEX_SHADER, include_str!("shaders/envgen.vs.glsl")),
(glin::gl::FRAGMENT_SHADER, include_str!("shaders/brdf_lut.fs.glsl")),
],
bindings: ::gl::default_attribute_bindings(),
.. Default::default()
}, get_cloth_ashikhmin_brdf_lut_program, CLOTH_ASHIKHMIN_LUT_SHADER);
program_cache!(glin::program::Settings{
version: ::gl::default_glsl_version(),
extensions: vec![],
precission: glin::program::ShaderPrecision::High,
defines: vec![
("MATERIAL_TYPE", "CLOTH_MATERIAL"),
("BRDF_CLOTH_D", "SPECULAR_D_CHARLIE"),
],
shaders: vec![
(glin::gl::VERTEX_SHADER, include_str!("shaders/envgen.vs.glsl")),
(glin::gl::FRAGMENT_SHADER, include_str!("shaders/brdf_lut.fs.glsl")),
],
bindings: ::gl::default_attribute_bindings(),
.. Default::default()
}, get_cloth_charlie_brdf_lut_program, CLOTH_CHARLIE_LUT_SHADER);
program_cache!("shaders/envgen.vs.glsl", "shaders/irradiance.fs.glsl", get_irradiance_program, IRR_SHADER);
program_cache!("shaders/envgen.vs.glsl", "shaders/radiance.fs.glsl", get_radiance_program, RAD_SHADER);
}
}