11use 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
56pub 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