Skip to content

Commit b939ab9

Browse files
committed
support more DC images
1 parent 0bad130 commit b939ab9

File tree

7 files changed

+78
-24
lines changed

7 files changed

+78
-24
lines changed

kidfile/src/archive_formats/afs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub const ENTRY_AFS: Decoder<Archive> = Decoder {
3434
let name = String::from_utf8(name_buf[0..len].to_vec()).map_err(|_| "entry name is not valid UTF-8")?;
3535
entries.push(ArchiveEntry {
3636
name: name.clone(),
37-
data: file.subfile(entry_ranges[i].0, entry_ranges[i].1, name.into()).unwrap(),
37+
data: file.subfile(entry_ranges[i].0, entry_ranges[i].1).unwrap(),
3838
timestamp: Some((year, month, day, hour, minute, second))
3939
});
4040
}

kidfile/src/archive_formats/concat2k.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub const ENTRY_CONCAT2K: Decoder<Archive> = Decoder {
3333
let name = entries.len().to_string();
3434
entries.push(ArchiveEntry {
3535
name: name.clone(),
36-
data: file.subfile(cur_entry_start, file.len() - cur_entry_start, name.into()).unwrap(),
36+
data: file.subfile(cur_entry_start, file.len() - cur_entry_start).unwrap(),
3737
timestamp: None
3838
});
3939
if entries.len() > 1 {
@@ -46,7 +46,7 @@ pub const ENTRY_CONCAT2K: Decoder<Archive> = Decoder {
4646
let name = entries.len().to_string();
4747
entries.push(ArchiveEntry {
4848
name: name.clone(),
49-
data: file.subfile(cur_entry_start, boundary - cur_entry_start, name.into()).unwrap(),
49+
data: file.subfile(cur_entry_start, boundary - cur_entry_start).unwrap(),
5050
timestamp: None
5151
});
5252
cur_entry_start = boundary;

kidfile/src/archive_formats/lnk.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub const ENTRY_LNK: Decoder<Archive> = Decoder {
2424
let name = String::from_utf8(name_buf[0..name_len].to_vec()).map_err(|_| "entry name is not valid UTF-8")?;
2525
entries.push(ArchiveEntry {
2626
name: name.clone(),
27-
data: file.subfile(data_section_start + offset as usize, len as usize, name.into()).unwrap(),
27+
data: file.subfile(data_section_start + offset as usize, len as usize).unwrap(),
2828
timestamp: None
2929
});
3030
index_ptr += 32;

kidfile/src/file_data.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ impl FileData {
6060
}
6161
}
6262

63-
pub fn subfile(&mut self, sub_start: usize, sub_size: usize, file_name: OsString) -> Result<FileData, String> {
63+
pub fn subfile(&mut self, sub_start: usize, sub_size: usize) -> Result<FileData, String> {
6464
match self {
6565
Self::Stream {path, start, size, ..} => {
6666
if sub_start + sub_size > *size {

kidfile/src/image.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ fn bits_6_to_8(x: u8) -> u8 {
131131
x << 2 | (x & 1) << 1 | (x & 1)
132132
}
133133

134+
fn bit_twiddle(x: usize) -> usize {
135+
(x & 1) | (x & 2) << 1 | (x & 4) << 2 | (x & 8) << 3 | (x & 16) << 4 | (x & 32) << 5 | (x & 64) << 6 | (x & 128) << 7 | (x & 256) << 8 | (x & 512) << 9
136+
}
137+
134138
impl Frame {
135139
pub fn empty(width: u32, height: u32, og_fmt: PixelFormat) -> Self {
136140
Self {
@@ -504,6 +508,19 @@ impl Frame {
504508
self
505509
}
506510

511+
pub fn twiddled_dc(mut self) -> Self {
512+
let mut pixels = Vec::with_capacity(self.pixels.len());
513+
for y in 0..self.width as usize {
514+
let twiddled_y = bit_twiddle(y);
515+
for x in 0..self.height as usize {
516+
pixels.push(self.pixels[twiddled_y | bit_twiddle(x) << 1]);
517+
}
518+
}
519+
self.pixels = pixels.into();
520+
std::mem::swap(&mut self.width, &mut self.height);
521+
self
522+
}
523+
507524
pub fn paste(&mut self, x: u32, y: u32, o: &Frame) {
508525
let end_x = (x + o.width).min(self.width);
509526
let end_y = (y + o.height).min(self.height);

kidfile/src/image_formats/bip.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::{byte_slice::ByteSlice, image::{Frame, Image, PixelFormat}, Certainty
33
pub const ENTRY_BIP: Decoder<Image> = Decoder {
44
id: "bip",
55
desc: "Remember11 image format",
6-
detect: |file| Certainty::certain_if(file.starts_with(&[5, 0, 0, 0]) || file.starts_with(&[10, 0, 0, 0])),
6+
detect: |file| Certainty::certain_if(matches!(file.get_u32_at(0), Some(5 | 10))),
77
decode: |file| {
88
let mut frames = Vec::new();
99
let bytes = file.read();

kidfile/src/image_formats/pvr.rs

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,74 @@
11
use crate::{byte_slice::ByteSlice, image::{Frame, Image}, Certainty, Decoder};
22

33
// https://www.fabiensanglard.net/Mykaruga/tools/segaPVRFormat.txt
4+
// https://dreamcast.wiki/Twiddling
45

56
pub const ENTRY_PVR: Decoder<Image> = Decoder {
67
id: "pvr",
78
desc: "Dreamcast image format",
8-
detect: |file| Certainty::certain_if(file.starts_with(b"PVRT") || (file.starts_with(b"GBIX") && file.starts_with_at(b"PVRT", 16))),
9+
detect: |file| {
10+
let file_start = if file.starts_with(b"GBIX") {16} else {0};
11+
Certainty::certain_if(file.starts_with_at(b"PVRT", file_start) || file.starts_with_at(b"PVPL", file_start))
12+
},
913
decode: |file| {
10-
let gbix = file.starts_with(b"GBIX");
11-
let file_len = file.read_u32(if gbix {20} else {4})? as usize;
14+
let mut file_start = if file.starts_with(b"GBIX") {16} else {0};
15+
let mut palette_bytes = Default::default();
16+
if file.starts_with_at(b"PVPL", file_start) {
17+
let palette_len = file.read_u32(file_start + 4)? as usize;
18+
palette_bytes = unsafe {Box::new_uninit_slice(palette_len - 8).assume_init()};
19+
file.read_chunk_exact(&mut palette_bytes, file_start + 16).map_err(|_| "PVPL length field is incorrect")?;
20+
file_start += palette_len + 8;
21+
};
22+
let file_len = file.read_u32(file_start + 4)? as usize;
1223
let mut buf = unsafe {Box::new_uninit_slice(file_len + 8).assume_init()};
13-
file.read_chunk_exact(&mut buf, if gbix {16} else {0}).map_err(|_| "file length field is incorrect")?;
24+
file.read_chunk_exact(&mut buf, file_start).map_err(|_| "PVRT length field is incorrect")?;
25+
if !buf.starts_with(b"PVRT") {
26+
return Err(format!("PVRT header not found, expected at {:#X}", file_start));
27+
}
1428
let pixel_fmt = buf.read_u8(8)?;
1529
let twiddle_type = buf.read_u8(9)?;
1630
println!("twiddle type {twiddle_type}");
1731
let width = buf.read_u16(12)? as usize;
1832
let height = buf.read_u16(14)? as usize;
19-
let frame = match pixel_fmt {
20-
0 => Frame::from_bgra16(width as u32, height as u32, buf.get(16..16 + width * height * 2).ok_or("not enough pixel data")?),
21-
1 => Frame::from_bgr16(width as u32, height as u32, buf.get(16..16 + width * height * 2).ok_or("not enough pixel data")?),
22-
2 => Frame::from_bgra4444(width as u32, height as u32, buf.get(16..16 + width * height * 2).ok_or("not enough pixel data")?),
23-
5 => Frame::from_rgba_clut4(
24-
width as u32, height as u32,
25-
buf.get(16..16 + 1024).ok_or("not enough palette data")?,
26-
buf.get(16 + 1024..16 + 1024 + width * height / 2).ok_or("not enough pixel data")?
27-
),
28-
6 => Frame::from_rgba_clut8(
29-
width as u32, height as u32,
30-
buf.get(16..16 + 1024).ok_or("not enough palette data")?,
31-
buf.get(16 + 1024..16 + 1024 + width * height).ok_or("not enough pixel data")?
32-
),
33+
let mut frame = match pixel_fmt {
34+
0 => Frame::from_bgra16(width as u32, height as u32, buf.get(16..16 + width * height * 2).ok_or("not enough pixel data for BGRA5551")?),
35+
1 => Frame::from_bgr16(width as u32, height as u32, buf.get(16..16 + width * height * 2).ok_or("not enough pixel data for BGR565")?),
36+
2 => Frame::from_bgra4444(width as u32, height as u32, buf.get(16..16 + width * height * 2).ok_or("not enough pixel data for BGRA4444")?),
37+
5 => {
38+
if palette_bytes.is_empty() {
39+
Frame::from_bgra_clut4(
40+
width as u32, height as u32,
41+
buf.get(16..16 + 1024).ok_or("not enough palette data for BGRA clut4")?,
42+
buf.get(16 + 1024..16 + 1024 + width * height / 2).ok_or("not enough pixel data for BGRA clut4")?
43+
)
44+
} else {
45+
Frame::from_bgra_clut4(
46+
width as u32, height as u32,
47+
&palette_bytes,
48+
buf.get(16..16 + width * height / 2).ok_or("not enough pixel data for BGRA clut4")?
49+
)
50+
}
51+
}
52+
6 => {
53+
if palette_bytes.is_empty() {
54+
Frame::from_bgra_clut8(
55+
width as u32, height as u32,
56+
buf.get(16..16 + 1024).ok_or("not enough palette data for BGRA clut8")?,
57+
buf.get(16 + 1024..16 + 1024 + width * height).ok_or("not enough pixel data for BGRA clut8")?
58+
)
59+
} else {
60+
Frame::from_bgra_clut8(
61+
width as u32, height as u32,
62+
&palette_bytes,
63+
buf.get(16..16 + width * height).ok_or("not enough pixel data for BGRA clut8")?
64+
)
65+
}
66+
}
3367
_ => return Err(format!("unhandled PVR pixel format {pixel_fmt}"))
3468
};
69+
if [1, 2, 5, 6, 7, 8, 13].contains(&twiddle_type) {
70+
frame = frame.twiddled_dc();
71+
}
3572
Ok(Image {frames: Box::new([frame])})
3673
}
3774
};

0 commit comments

Comments
 (0)