use rin_math::pnt2;
use rin_graphics::{self as graphics, Mesh, Vertex2DTex};
#[cfg(feature="dds")]
#[doc(inline)]
pub use self::generate_dds::*;
fn full_screen_quad() -> Mesh<Vertex2DTex>{
graphics::rectangle_texcoords(&pnt2(-1., -1.), 2., 2., 0., 0., 1., 1.)
}
#[cfg(feature="dds")]
mod generate_dds{
use glin;
use crate::graphics;
use crate::gl::{Renderer2d, ShaderMaterial, Renderer};
use color::consts::BLACK;
use crate::graphics::dds::{self, Dds};
use std::mem;
use std::slice;
use crate::util::LogErr;
use glin::{gl, gl::types::*};
use glin::uniforms;
#[cfg(all(feature = "gl", not(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::R16 |
glin::fbo::ColorFormat::R16F |
glin::fbo::ColorFormat::R32F => dds::Format::Gray,
glin::fbo::ColorFormat::RG8 |
glin::fbo::ColorFormat::RG16 |
glin::fbo::ColorFormat::RG16F |
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(not(any(feature="gles", feature="webgl")))]
material.set_properties(vec![
glin::Property::TextureCubemapSeamless(true),
]);
let mut dds_data = vec![ ];
let 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 = &fbos[mip as usize];
{
let gl = gl.with_fbo(fbo);
gl.clear(&BLACK);
gl.draw_mesh_with_material(&super::full_screen_quad(), &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(not(any(feature="gles", feature="webgl")))]
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(&fbo)
.draw_mesh_with_material(&super::full_screen_quad(), &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(not(any(feature="gles", feature="webgl")))]
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(&fbo)
.draw_mesh_with_material(&super::full_screen_quad(), &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 crate::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(),
precision: 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(not(any(feature="gles", feature="webgl")))]
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::{self, gl, gl::types::*, uniforms};
use color::consts::BLACK;
use std::borrow::Borrow;
use crate::{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 fbo = gl.new_fbo().from_color_no_depth(color).unwrap();
let mut material = ShaderMaterial::new(program);
#[cfg(not(any(feature="gles", feature="webgl")))]
material.set_properties(vec![
glin::Property::TextureCubemapSeamless(true),
]);
{
let uniforms = uniforms!{
cubemap: cubemap,
level: level as i32,
};
material.set_uniforms(uniforms);
gl.with_fbo(&fbo)
.draw_mesh_with_material(&super::full_screen_quad(), &material);
}
let (color, _depth) = fbo.into_attachments();
if let glin::fbo::ColorAttachment::TextureLevel(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 mut cubemap = gl.new_cubemap().from_format(glin::cubemap::Format{
internal_format: color_format as GLenum,
width: size,
height: size,
levels: 1,
}).unwrap();
copy_equirectangular_to_cubemap(map, &mut cubemap, gl);
cubemap
}
pub fn copy_equirectangular_to_cubemap(
map: &glin::Texture,
cubemap: &mut glin::CubeMap,
gl: &Renderer)
{
let program = shaders::get_equirectangular_program(gl);
let mut material = ShaderMaterial::new(program);
#[cfg(not(any(feature="gles", feature="webgl")))]
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(&super::full_screen_quad(), &material);
}
}
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(not(any(feature="gles", feature="webgl")))]
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(&super::full_screen_quad(), &material);
}
cubemap
}
pub fn copy_equirectangular_levels_to_cubemap<'a, T, I>(
levels: I,
cubemap: &mut glin::CubeMap,
gl: &Renderer)
where T: Borrow<glin::Texture>, I: IntoIterator<Item = T>
{
let program = shaders::get_equirectangular_program(gl);
let mut material = ShaderMaterial::new(program);
#[cfg(not(any(feature="gles", feature="webgl")))]
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(&super::full_screen_quad(), &material);
}
}
}
pub fn equirectangular_levels_to_cubemap<'a, T, I>(
levels: I,
size: u32,
color_format:
glin::fbo::ColorFormat, gl: &Renderer) -> glin::CubeMap
where T: Borrow<glin::Texture>, I: IntoIterator<Item = T>
{
let mut cubemap = gl.new_cubemap().from_format(glin::cubemap::Format{
internal_format: color_format as GLenum,
width: size,
height: size,
levels: (size as f32).log2().floor() as u32 + 1,
}).unwrap();
copy_equirectangular_levels_to_cubemap(levels, &mut cubemap, gl);
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 fbo = gl.new_fbo().from_color_no_depth(color).unwrap();
{
let gl = gl.with_fbo(&fbo);
gl.clear(&BLACK);
gl.draw_mesh_with_material(&super::full_screen_quad(), &program);
}
if let Some(glin::fbo::ColorAttachment::TextureLevel(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 fbo = gl.new_fbo().from_color_no_depth(color).unwrap();
{
let gl = gl.with_fbo(&fbo);
gl.clear(&BLACK);
gl.draw_mesh_with_material(&super::full_screen_quad(), &program);
}
if let Some(glin::fbo::ColorAttachment::TextureLevel(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 fbo = gl.new_fbo().from_color_no_depth(color).unwrap();
{
let gl = gl.with_fbo(&fbo);
gl.clear(&BLACK);
gl.draw_mesh_with_material(&super::full_screen_quad(), &program);
}
if let Some(glin::fbo::ColorAttachment::TextureLevel(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(&super::full_screen_quad(), &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(&super::full_screen_quad(), &material);
}
}
cubemap
}
mod shaders{
use glin;
program_cache!(glin::program::Settings{
version: crate::default_glsl_version(),
precision: 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: crate::default_attribute_bindings().clone(),
.. Default::default()
}, get_equirectangular_program, EQUI_SHADER);
program_cache!(glin::program::Settings{
version: crate::default_glsl_version(),
precision: 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: crate::default_attribute_bindings().clone(),
.. Default::default()
}, get_to_equirectangular_program, TO_EQUI_SHADER);
program_cache!(glin::program::Settings{
version: crate::default_glsl_version(),
extensions: vec![],
precision: 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: crate::default_attribute_bindings().clone(),
.. Default::default()
}, get_brdf_lut_program, LUT_SHADER);
program_cache!(glin::program::Settings{
version: crate::default_glsl_version(),
extensions: vec![],
precision: 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: crate::default_attribute_bindings().clone(),
.. Default::default()
}, get_cloth_ashikhmin_brdf_lut_program, CLOTH_ASHIKHMIN_LUT_SHADER);
program_cache!(glin::program::Settings{
version: crate::default_glsl_version(),
extensions: vec![],
precision: 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: crate::default_attribute_bindings().clone(),
.. 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);
}
}