use bitflags::bitflags;
use super::{D3DFormat, DataFormat, DxgiFormat};
use crate::error::*;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::fmt;
use std::io::{Read, Write};
#[derive(Clone)]
pub struct PixelFormat {
pub size: u32,
pub flags: PixelFormatFlags,
pub fourcc: Option<FourCC>,
pub rgb_bit_count: Option<u32>,
pub r_bit_mask: Option<u32>,
pub g_bit_mask: Option<u32>,
pub b_bit_mask: Option<u32>,
pub a_bit_mask: Option<u32>,
}
impl PixelFormat {
pub fn read<R: Read>(mut r: R) -> Result<PixelFormat, Error> {
let size = r.read_u32::<LittleEndian>()?;
if size != 32 {
return Err(Error::InvalidField("Pixel format struct size".to_owned()));
}
let flags = PixelFormatFlags::from_bits_truncate(r.read_u32::<LittleEndian>()?);
let fourcc = r.read_u32::<LittleEndian>()?;
let rgb_bit_count = r.read_u32::<LittleEndian>()?;
let r_bit_mask = r.read_u32::<LittleEndian>()?;
let g_bit_mask = r.read_u32::<LittleEndian>()?;
let b_bit_mask = r.read_u32::<LittleEndian>()?;
let a_bit_mask = r.read_u32::<LittleEndian>()?;
Ok(PixelFormat {
size,
flags,
fourcc: if flags.contains(PixelFormatFlags::FOURCC) {
Some(FourCC(fourcc))
} else {
None
},
rgb_bit_count: if flags.contains(PixelFormatFlags::RGB)
|| flags.contains(PixelFormatFlags::LUMINANCE)
{
Some(rgb_bit_count)
} else {
None
},
r_bit_mask: if flags.contains(PixelFormatFlags::RGB) {
Some(r_bit_mask)
} else {
None
},
g_bit_mask: if flags.contains(PixelFormatFlags::RGB) {
Some(g_bit_mask)
} else {
None
},
b_bit_mask: if flags.contains(PixelFormatFlags::RGB) {
Some(b_bit_mask)
} else {
None
},
a_bit_mask: if flags.contains(PixelFormatFlags::ALPHA_PIXELS)
|| flags.contains(PixelFormatFlags::ALPHA)
{
Some(a_bit_mask)
} else {
None
},
})
}
pub fn write<W: Write>(&self, w: &mut W) -> Result<(), Error> {
w.write_u32::<LittleEndian>(self.size)?;
w.write_u32::<LittleEndian>(self.flags.bits())?;
w.write_u32::<LittleEndian>(self.fourcc.as_ref().unwrap_or(&FourCC(0)).0)?;
w.write_u32::<LittleEndian>(self.rgb_bit_count.unwrap_or(0))?;
w.write_u32::<LittleEndian>(self.r_bit_mask.unwrap_or(0))?;
w.write_u32::<LittleEndian>(self.g_bit_mask.unwrap_or(0))?;
w.write_u32::<LittleEndian>(self.b_bit_mask.unwrap_or(0))?;
w.write_u32::<LittleEndian>(self.a_bit_mask.unwrap_or(0))?;
Ok(())
}
}
impl fmt::Debug for PixelFormat {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, " Pixel Format:")?;
writeln!(f, " flags: {:?}", self.flags)?;
writeln!(f, " fourcc: {:?}", self.fourcc)?;
writeln!(f, " bits_per_pixel: {:?}", self.rgb_bit_count)?;
writeln!(
f,
" RGBA bitmasks: {:?}, {:?}, {:?}, {:?}",
self.r_bit_mask, self.g_bit_mask, self.b_bit_mask, self.a_bit_mask
)?;
Ok(())
}
}
impl Default for PixelFormat {
fn default() -> PixelFormat {
PixelFormat {
size: 32, flags: PixelFormatFlags::empty(),
fourcc: None,
rgb_bit_count: None,
r_bit_mask: None,
g_bit_mask: None,
b_bit_mask: None,
a_bit_mask: None,
}
}
}
impl From<D3DFormat> for PixelFormat {
fn from(format: D3DFormat) -> PixelFormat {
let mut pf: PixelFormat = Default::default();
if let Some(bpp) = format.get_bits_per_pixel() {
pf.flags.insert(PixelFormatFlags::RGB);
pf.rgb_bit_count = Some(bpp as u32)
} else if let Some(fourcc) = format.get_fourcc() {
pf.flags.insert(PixelFormatFlags::FOURCC);
pf.fourcc = Some(fourcc);
}
if let Some(abitmask) = format.a_bit_mask() {
pf.flags.insert(PixelFormatFlags::ALPHA_PIXELS);
pf.a_bit_mask = Some(abitmask);
}
pf.r_bit_mask = format.r_bit_mask();
pf.g_bit_mask = format.g_bit_mask();
pf.b_bit_mask = format.b_bit_mask();
pf
}
}
impl From<DxgiFormat> for PixelFormat {
fn from(format: DxgiFormat) -> PixelFormat {
let mut pf: PixelFormat = Default::default();
if let Some(bpp) = format.get_bits_per_pixel() {
pf.flags.insert(PixelFormatFlags::RGB); pf.rgb_bit_count = Some(bpp as u32)
}
pf.fourcc = Some(FourCC(FourCC::DX10)); pf.flags.insert(PixelFormatFlags::FOURCC);
pf
}
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct PixelFormatFlags: u32 {
const ALPHA_PIXELS = 0x1;
const ALPHA = 0x2;
const FOURCC = 0x4;
const RGB = 0x40;
const YUV = 0x200;
const LUMINANCE = 0x20000;
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct FourCC(pub u32);
impl FourCC {
pub const NONE: u32 = 0;
pub const DXT1: u32 = 0x31545844; pub const DXT2: u32 = 0x32545844; pub const DXT3: u32 = 0x33545844; pub const DXT4: u32 = 0x34545844; pub const DXT5: u32 = 0x35545844; pub const R8G8_B8G8: u32 = 0x47424752; pub const G8R8_G8B8: u32 = 0x42475247; pub const A16B16G16R16: u32 = 36;
pub const Q16W16V16U16: u32 = 110;
pub const R16F: u32 = 111;
pub const G16R16F: u32 = 112;
pub const A16B16G16R16F: u32 = 113;
pub const R32F: u32 = 114;
pub const G32R32F: u32 = 115;
pub const A32B32G32R32F: u32 = 116;
pub const UYVY: u32 = 0x59565955; pub const YUY2: u32 = 0x32595559; pub const CXV8U8: u32 = 117;
pub const ATI1: u32 = 0x31495441; pub const ATI2: u32 = 0x32495441; pub const DX10: u32 = 0x30315844;
pub const BC1_UNORM: u32 = 0x31545844; pub const BC2_UNORM: u32 = 0x33545844; pub const BC3_UNORM: u32 = 0x35545844; pub const BC4_UNORM: u32 = 0x55344342; pub const BC4_SNORM: u32 = 0x53344342; pub const BC5_UNORM: u32 = 0x32495441; pub const BC5_SNORM: u32 = 0x53354342; pub const R8G8_B8G8_UNORM: u32 = 0x47424752; pub const G8R8_G8B8_UNORM: u32 = 0x42475247; pub const R16G16B16A16_UNORM: u32 = 36;
pub const R16G16B16A16_SNORM: u32 = 110;
pub const R16_FLOAT: u32 = 111;
pub const R16G16_FLOAT: u32 = 112;
pub const R16G16B16A16_FLOAT: u32 = 113;
pub const R32_FLOAT: u32 = 114;
pub const R32G32_FLOAT: u32 = 115;
pub const R32G32B32A32_FLOAT: u32 = 116;
}