141 lines
2.8 KiB
Rust
141 lines
2.8 KiB
Rust
//! Shapes file bitmap type.
|
|
|
|
use crate::{err::*, image::Image};
|
|
use super::clut;
|
|
|
|
/// Reads a `Bitmap`.
|
|
pub fn read(b: &[u8]) -> ResultS<Bitmap>
|
|
{
|
|
read_data! {
|
|
endian: BIG, buf: b, size: 26, start: 0, data {
|
|
let width = u16[0] usize;
|
|
let height = u16[2] usize;
|
|
let compr = u16[4];
|
|
let flags = u16[6] flag BmpFlags;
|
|
let depth = u16[8];
|
|
}
|
|
}
|
|
|
|
let compr = compr == u16::max_value();
|
|
let alpha = flags.contains(BmpFlags::TRANSPARENT);
|
|
let cmajr = flags.contains(BmpFlags::COLUMN_MAJOR);
|
|
|
|
if depth != 8 {
|
|
bail!("invalid bit depth (should always be 8)");
|
|
}
|
|
|
|
let mut bmp = Bitmap::new(width, height, alpha, cmajr);
|
|
let mut p = 30 + if cmajr {4 * width} else {4 * height};
|
|
|
|
let scanlines = if cmajr {width} else {height};
|
|
let pitch = if cmajr {height} else {width};
|
|
|
|
if compr {
|
|
// compressed scanlines (transparency RLE)
|
|
for _ in 0..scanlines {
|
|
read_data! {
|
|
endian: BIG, buf: b, size: 4, start: p, data {
|
|
let fst = u16[0] usize;
|
|
let lst = u16[2] usize;
|
|
}
|
|
}
|
|
|
|
let end = lst - fst;
|
|
|
|
p += 4;
|
|
|
|
if lst < fst || fst > pitch || lst > pitch {
|
|
bail!("invalid compressed scanline");
|
|
}
|
|
|
|
for _ in 0..fst {
|
|
bmp.cr.push(0);
|
|
}
|
|
|
|
bmp.cr.extend(ok!(b.get(p..p + end), "not enough data")?);
|
|
|
|
for _ in lst..pitch {
|
|
bmp.cr.push(0);
|
|
}
|
|
|
|
p += end;
|
|
}
|
|
} else {
|
|
// simple copy
|
|
bmp.cr.extend(ok!(b.get(p..p + width * height), "not enough data")?);
|
|
}
|
|
|
|
Ok(bmp)
|
|
}
|
|
|
|
impl Bitmap
|
|
{
|
|
/// Creates an empty bitmap.
|
|
pub fn new(w: usize, h: usize, alpha: bool, cmajr: bool) -> Self
|
|
{
|
|
Self{w, h, alpha, cmajr, cr: Vec::with_capacity(w * h)}
|
|
}
|
|
}
|
|
|
|
impl<'a, 'b> ImageShp<'a, 'b>
|
|
{
|
|
/// Creates an `ImageShp` with the given bitmap.
|
|
#[inline]
|
|
pub const fn new(bmp: &'a Bitmap, clut: &'b [clut::ColorShp]) -> Self
|
|
{
|
|
Self{bmp, clut}
|
|
}
|
|
}
|
|
|
|
impl Image for ImageShp<'_, '_>
|
|
{
|
|
type Output = clut::ColorShp;
|
|
|
|
fn w(&self) -> usize {self.bmp.w}
|
|
fn h(&self) -> usize {self.bmp.h}
|
|
|
|
fn index(&self, x: usize, y: usize) -> &Self::Output
|
|
{
|
|
static TRANSLUCENT_COLOR: clut::ColorShp = clut::ColorShp::Translucent;
|
|
|
|
let cr = usize::from(if self.bmp.cmajr {
|
|
self.bmp.cr[y + x * self.bmp.h]
|
|
} else {
|
|
self.bmp.cr[x + y * self.bmp.w]
|
|
});
|
|
|
|
if self.bmp.alpha && cr == 0 {
|
|
&TRANSLUCENT_COLOR
|
|
} else {
|
|
self.clut.get(cr).unwrap_or(&TRANSLUCENT_COLOR)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// An unpacked Shape bitmap.
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
pub struct Bitmap {
|
|
w: usize,
|
|
h: usize,
|
|
cr: Vec<u8>,
|
|
alpha: bool,
|
|
cmajr: bool,
|
|
}
|
|
|
|
/// An image from a Shape. This mainly just exists so that `Bitmap` can use the
|
|
/// `Image` trait.
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub struct ImageShp<'a, 'b> {
|
|
bmp: &'a Bitmap,
|
|
clut: &'b [clut::ColorShp],
|
|
}
|
|
|
|
c_bitfield! {
|
|
pub struct BmpFlags: u16 {
|
|
TRANSPARENT = 14,
|
|
COLUMN_MAJOR = 15,
|
|
}
|
|
}
|
|
|
|
// EOF
|