mod srgb;
pub use srgb::{store_bgr8_srgb_f32, store_bgra8_srgb_f32, store_srgb8_f32};
use half::f16;
use super::buffer::Buffer;
pub fn store_u8_unorm_f32(buf: &Buffer<f32>, channels: usize) -> Vec<u8> {
profiling::scope!("store_u8_unorm_f32");
write_pixels(buf, channels, 1, |lanes, bytes| {
for (&lane, byte) in lanes.iter().zip(bytes.iter_mut()) {
*byte = (lane.clamp(0.0, 1.0) * 255.0).round() as u8;
}
})
}
pub fn store_i8_snorm_f32(buf: &Buffer<f32>, channels: usize) -> Vec<u8> {
profiling::scope!("store_i8_snorm_f32");
write_pixels(buf, channels, 1, |lanes, bytes| {
for (&lane, byte) in lanes.iter().zip(bytes.iter_mut()) {
let v = (lane.clamp(-1.0, 1.0) * 127.0).round() as i8;
*byte = v as u8;
}
})
}
pub fn store_bgra8_unorm_f32(buf: &Buffer<f32>) -> Vec<u8> {
profiling::scope!("store_bgra8_unorm_f32");
write_pixels(buf, 4, 1, |lanes, bytes| {
let arr = <&mut [u8; 4]>::try_from(bytes).expect("4-byte pixel");
arr[0] = (lanes[2].clamp(0.0, 1.0) * 255.0).round() as u8; arr[1] = (lanes[1].clamp(0.0, 1.0) * 255.0).round() as u8; arr[2] = (lanes[0].clamp(0.0, 1.0) * 255.0).round() as u8; arr[3] = (lanes[3].clamp(0.0, 1.0) * 255.0).round() as u8; })
}
pub fn store_bgr8_unorm_f32(buf: &Buffer<f32>) -> Vec<u8> {
profiling::scope!("store_bgr8_unorm_f32");
write_pixels(buf, 3, 1, |lanes, bytes| {
let arr = <&mut [u8; 3]>::try_from(bytes).expect("3-byte pixel");
arr[0] = (lanes[2].clamp(0.0, 1.0) * 255.0).round() as u8;
arr[1] = (lanes[1].clamp(0.0, 1.0) * 255.0).round() as u8;
arr[2] = (lanes[0].clamp(0.0, 1.0) * 255.0).round() as u8;
})
}
pub fn store_u16_unorm_f32(buf: &Buffer<f32>, channels: usize) -> Vec<u8> {
profiling::scope!("store_u16_unorm_f32");
write_pixels(buf, channels, 2, |lanes, bytes| {
let (chunks, _) = bytes.as_chunks_mut::<2>();
for (&lane, chunk) in lanes.iter().zip(chunks) {
let v = (lane.clamp(0.0, 1.0) * 65535.0).round() as u16;
*chunk = v.to_le_bytes();
}
})
}
pub fn store_i16_snorm_f32(buf: &Buffer<f32>, channels: usize) -> Vec<u8> {
profiling::scope!("store_i16_snorm_f32");
write_pixels(buf, channels, 2, |lanes, bytes| {
let (chunks, _) = bytes.as_chunks_mut::<2>();
for (&lane, chunk) in lanes.iter().zip(chunks) {
let v = (lane.clamp(-1.0, 1.0) * 32767.0).round() as i16;
*chunk = v.to_le_bytes();
}
})
}
pub fn store_f16_f32(buf: &Buffer<f32>, channels: usize) -> Vec<u8> {
profiling::scope!("store_f16_f32");
write_pixels(buf, channels, 2, |lanes, bytes| {
let (chunks, _) = bytes.as_chunks_mut::<2>();
for (&lane, chunk) in lanes.iter().zip(chunks) {
*chunk = f16::from_f32(lane).to_le_bytes();
}
})
}
pub fn store_f32_f32(buf: &Buffer<f32>, channels: usize) -> Vec<u8> {
profiling::scope!("store_f32_f32");
write_pixels(buf, channels, 4, |lanes, bytes| {
let (chunks, _) = bytes.as_chunks_mut::<4>();
for (&lane, chunk) in lanes.iter().zip(chunks) {
*chunk = lane.to_le_bytes();
}
})
}
pub fn store_f32_f64(buf: &Buffer<f64>, channels: usize) -> Vec<u8> {
profiling::scope!("store_f32_f64");
write_pixels_f64(buf, channels, 4, |lanes, bytes| {
let (chunks, _) = bytes.as_chunks_mut::<4>();
for (&lane, chunk) in lanes.iter().zip(chunks) {
*chunk = (lane as f32).to_le_bytes();
}
})
}
pub fn store_f64_f64(buf: &Buffer<f64>, channels: usize) -> Vec<u8> {
profiling::scope!("store_f64_f64");
write_pixels_f64(buf, channels, 8, |lanes, bytes| {
let (chunks, _) = bytes.as_chunks_mut::<8>();
for (&lane, chunk) in lanes.iter().zip(chunks) {
*chunk = lane.to_le_bytes();
}
})
}
pub fn store_u8_uint_u32(buf: &Buffer<u32>, channels: usize) -> Vec<u8> {
profiling::scope!("store_u8_uint_u32");
write_pixels_u32(buf, channels, 1, |lanes, bytes| {
for (&lane, byte) in lanes.iter().zip(bytes.iter_mut()) {
*byte = lane.min(u8::MAX as u32) as u8;
}
})
}
pub fn store_i8_sint_u32(buf: &Buffer<u32>, channels: usize) -> Vec<u8> {
profiling::scope!("store_i8_sint_u32");
write_pixels_u32(buf, channels, 1, |lanes, bytes| {
for (&lane, byte) in lanes.iter().zip(bytes.iter_mut()) {
let v = (lane as i32).clamp(i8::MIN as i32, i8::MAX as i32) as i8;
*byte = v as u8;
}
})
}
pub fn store_u16_uint_u32(buf: &Buffer<u32>, channels: usize) -> Vec<u8> {
profiling::scope!("store_u16_uint_u32");
write_pixels_u32(buf, channels, 2, |lanes, bytes| {
let (chunks, _) = bytes.as_chunks_mut::<2>();
for (&lane, chunk) in lanes.iter().zip(chunks) {
let v = lane.min(u16::MAX as u32) as u16;
*chunk = v.to_le_bytes();
}
})
}
pub fn store_i16_sint_u32(buf: &Buffer<u32>, channels: usize) -> Vec<u8> {
profiling::scope!("store_i16_sint_u32");
write_pixels_u32(buf, channels, 2, |lanes, bytes| {
let (chunks, _) = bytes.as_chunks_mut::<2>();
for (&lane, chunk) in lanes.iter().zip(chunks) {
let v = (lane as i32).clamp(i16::MIN as i32, i16::MAX as i32) as i16;
*chunk = v.to_le_bytes();
}
})
}
pub fn store_u32_uint_u32(buf: &Buffer<u32>, channels: usize) -> Vec<u8> {
profiling::scope!("store_u32_uint_u32");
write_pixels_u32(buf, channels, 4, |lanes, bytes| {
let (chunks, _) = bytes.as_chunks_mut::<4>();
for (&lane, chunk) in lanes.iter().zip(chunks) {
*chunk = lane.to_le_bytes();
}
})
}
pub fn store_i32_sint_u32(buf: &Buffer<u32>, channels: usize) -> Vec<u8> {
profiling::scope!("store_i32_sint_u32");
write_pixels_u32(buf, channels, 4, |lanes, bytes| {
let (chunks, _) = bytes.as_chunks_mut::<4>();
for (&lane, chunk) in lanes.iter().zip(chunks) {
*chunk = lane.to_le_bytes();
}
})
}
pub fn store_u64_uint_u64(buf: &Buffer<u64>, channels: usize) -> Vec<u8> {
profiling::scope!("store_u64_uint_u64");
write_pixels_u64(buf, channels, 8, |lanes, bytes| {
let (chunks, _) = bytes.as_chunks_mut::<8>();
for (&lane, chunk) in lanes.iter().zip(chunks) {
*chunk = lane.to_le_bytes();
}
})
}
pub fn store_i64_sint_u64(buf: &Buffer<u64>, channels: usize) -> Vec<u8> {
profiling::scope!("store_i64_sint_u64");
write_pixels_u64(buf, channels, 8, |lanes, bytes| {
let (chunks, _) = bytes.as_chunks_mut::<8>();
for (&lane, chunk) in lanes.iter().zip(chunks) {
*chunk = lane.to_le_bytes();
}
})
}
fn write_pixels(
buf: &Buffer<f32>,
channels: usize,
channel_bytes: usize,
mut encode: impl FnMut(&[f32; 4], &mut [u8]),
) -> Vec<u8> {
let pixel_bytes = channels * channel_bytes;
let mut out = vec![0u8; buf.pixels.len() * pixel_bytes];
for (pixel, bytes) in buf.pixels.iter().zip(out.chunks_exact_mut(pixel_bytes)) {
encode(pixel, bytes);
}
out
}
fn write_pixels_f64(
buf: &Buffer<f64>,
channels: usize,
channel_bytes: usize,
mut encode: impl FnMut(&[f64; 4], &mut [u8]),
) -> Vec<u8> {
let pixel_bytes = channels * channel_bytes;
let mut out = vec![0u8; buf.pixels.len() * pixel_bytes];
for (pixel, bytes) in buf.pixels.iter().zip(out.chunks_exact_mut(pixel_bytes)) {
encode(pixel, bytes);
}
out
}
fn write_pixels_u32(
buf: &Buffer<u32>,
channels: usize,
channel_bytes: usize,
mut encode: impl FnMut(&[u32; 4], &mut [u8]),
) -> Vec<u8> {
let pixel_bytes = channels * channel_bytes;
let mut out = vec![0u8; buf.pixels.len() * pixel_bytes];
for (pixel, bytes) in buf.pixels.iter().zip(out.chunks_exact_mut(pixel_bytes)) {
encode(pixel, bytes);
}
out
}
fn write_pixels_u64(
buf: &Buffer<u64>,
channels: usize,
channel_bytes: usize,
mut encode: impl FnMut(&[u64; 4], &mut [u8]),
) -> Vec<u8> {
let pixel_bytes = channels * channel_bytes;
let mut out = vec![0u8; buf.pixels.len() * pixel_bytes];
for (pixel, bytes) in buf.pixels.iter().zip(out.chunks_exact_mut(pixel_bytes)) {
encode(pixel, bytes);
}
out
}