use std::path::Path;
use crate::context::Context;
pub struct Environment {
pub view: wgpu::TextureView,
pub sampler: wgpu::Sampler,
pub present: bool,
}
impl Environment {
pub fn fallback() -> Environment {
Self::from_rgba_f32(1, 1, &[0.0, 0.0, 0.0, 1.0], false)
}
pub fn from_file(path: &Path) -> Option<Environment> {
let img = image::open(path).ok()?;
Some(Self::from_image(&img))
}
pub fn from_image(img: &image::DynamicImage) -> Environment {
use image::GenericImageView;
let (w, h) = img.dimensions();
let rgb = img.to_rgba32f();
Self::from_rgba_f32(w, h, rgb.as_raw(), true)
}
pub fn from_rgba_f32(width: u32, height: u32, rgba: &[f32], present: bool) -> Environment {
let ctxt = Context::get();
let halves: Vec<u16> = rgba.iter().map(|&v| f32_to_f16(v)).collect();
let texture = ctxt.create_texture(&wgpu::TextureDescriptor {
label: Some("rt_environment"),
size: wgpu::Extent3d {
width,
height,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba16Float,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
view_formats: &[],
});
ctxt.write_texture(
wgpu::TexelCopyTextureInfo {
texture: &texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
},
bytemuck::cast_slice(&halves),
wgpu::TexelCopyBufferLayout {
offset: 0,
bytes_per_row: Some(width * 8), rows_per_image: Some(height),
},
wgpu::Extent3d {
width,
height,
depth_or_array_layers: 1,
},
);
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
let sampler = ctxt.create_sampler(&wgpu::SamplerDescriptor {
label: Some("rt_environment_sampler"),
address_mode_u: wgpu::AddressMode::Repeat,
address_mode_v: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Linear,
..Default::default()
});
Environment {
view,
sampler,
present,
}
}
}
fn f32_to_f16(value: f32) -> u16 {
let bits = value.to_bits();
let sign = ((bits >> 16) & 0x8000) as u16;
let exp = ((bits >> 23) & 0xff) as i32 - 127 + 15;
let mant = (bits >> 13) & 0x3ff;
if exp <= 0 {
sign } else if exp >= 0x1f {
sign | 0x7c00 } else {
sign | ((exp as u16) << 10) | (mant as u16)
}
}