@@ -13,104 +13,120 @@ pub const ENTRY_PVR: Decoder<Image> = Decoder {
1313 Certainty :: certain_if ( file. starts_with_at ( b"PVRT" , file_start) || file. starts_with_at ( b"PVPL" , file_start) )
1414 } ,
1515 decode : |file| {
16- let mut file_start = if file. starts_with ( b"GBIX" ) { 16 } else { 0 } ;
17- let mut palette_bytes = Default :: default ( ) ;
18- if file. starts_with_at ( b"PVPL" , file_start) {
19- let palette_len = file. read_u32 ( file_start + 4 ) ? as usize ;
20- palette_bytes = unsafe { Box :: new_uninit_slice ( palette_len - 8 ) . assume_init ( ) } ;
21- file. read_chunk_exact ( & mut palette_bytes, file_start + 16 ) . map_err ( |_| "PVPL length field is incorrect" ) ?;
22- file_start += palette_len + 8 ;
23- } ;
24- let file_len = file. read_u32 ( file_start + 4 ) ? as usize ;
25- let mut buf = unsafe { Box :: new_uninit_slice ( file_len + 8 ) . assume_init ( ) } ;
26- file. read_chunk_exact ( & mut buf, file_start) . map_err ( |_| "PVRT length field is incorrect" ) ?;
27- if !buf. starts_with ( b"PVRT" ) {
28- return Err ( format ! ( "PVRT header not found, expected at {:#X}" , file_start) ) ;
16+ let mut file_start = 0 ;
17+ let mut tex_start = 0 ;
18+ let mut tex_len = 0 ;
19+ let mut palettes = Vec :: new ( ) ;
20+ while file_start < file. len ( ) {
21+ let file_len = file. read_u32 ( file_start + 4 ) ? as usize ;
22+ if file. starts_with_at ( b"PVPL" , file_start) {
23+ let mut palette_bytes = Default :: default ( ) ;
24+ palette_bytes = unsafe { Box :: new_uninit_slice ( file_len - 8 ) . assume_init ( ) } ;
25+ file. read_chunk_exact ( & mut palette_bytes, file_start + 16 ) . map_err ( |_| "PVPL length field is incorrect" ) ?;
26+ palettes. push ( palette_bytes) ;
27+ } else if file. starts_with_at ( b"PVRT" , file_start) {
28+ tex_start = file_start;
29+ tex_len = file_len;
30+ }
31+ file_start += file_len + 8 ;
32+ }
33+ if tex_len <= 0 {
34+ return Err ( "PVRT header not found in file" . to_string ( ) ) ;
2935 }
36+ let mut buf = unsafe { Box :: new_uninit_slice ( tex_len + 8 ) . assume_init ( ) } ;
37+ file. read_chunk_exact ( & mut buf, tex_start) . map_err ( |_| "PVRT length field is incorrect" ) ?;
3038 let pixel_fmt = buf. read_u8 ( 8 ) ?;
3139 let twiddle_type = buf. read_u8 ( 9 ) ?;
3240 println ! ( "twiddle type {twiddle_type}" ) ;
3341 let width = buf. read_u16 ( 12 ) ? as usize ;
3442 let height = buf. read_u16 ( 14 ) ? as usize ;
35- let mut frame = match pixel_fmt {
36- 0 | 1 | 2 => {
37- if twiddle_type == 3 { // vq compression
38- let codebook = buf. get ( 16 ..16 + 2048 ) . ok_or ( "not enough 16-bit VQ codebook data" ) ?;
39- let indices = buf. get ( 16 + 2048 ..16 + 2048 + width * height / 4 ) . ok_or ( "not enough VQ index data" ) ?;
40- let mut pixels = vec ! [ 0u8 ; width * height * 2 ] ;
41- for block_y in 0 ..height / 2 {
42- let twiddled_block_y = bit_twiddle ( block_y) ;
43- for block_x in 0 ..width / 2 {
44- let twiddled_block_idx = twiddled_block_y | bit_twiddle ( block_x) << 1 ;
45- let codebook_pos = indices[ twiddled_block_idx] as usize * 8 ;
46- let x = block_x * 2 ;
47- let y = block_y * 2 ;
48- pixels[ ( y * width + x) * 2 ] = codebook[ codebook_pos] ;
49- pixels[ ( y * width + x) * 2 + 1 ] = codebook[ codebook_pos + 1 ] ;
50- pixels[ ( y * width + x + 1 ) * 2 ] = codebook[ codebook_pos + 4 ] ;
51- pixels[ ( y * width + x + 1 ) * 2 + 1 ] = codebook[ codebook_pos + 5 ] ;
52- pixels[ ( ( y + 1 ) * width + x) * 2 ] = codebook[ codebook_pos + 2 ] ;
53- pixels[ ( ( y + 1 ) * width + x) * 2 + 1 ] = codebook[ codebook_pos + 3 ] ;
54- pixels[ ( ( y + 1 ) * width + x + 1 ) * 2 ] = codebook[ codebook_pos + 6 ] ;
55- pixels[ ( ( y + 1 ) * width + x + 1 ) * 2 + 1 ] = codebook[ codebook_pos + 7 ] ;
43+ let mut frames = Vec :: new ( ) ;
44+ if palettes. len ( ) == 0 {
45+ let palette_bytes = unsafe { Box :: new_uninit_slice ( 0 ) . assume_init ( ) } ;
46+ palettes. push ( palette_bytes) ;
47+ }
48+ for palette_bytes in palettes. iter ( ) {
49+ let mut frame = match pixel_fmt {
50+ 0 | 1 | 2 => {
51+ if twiddle_type == 3 { // vq compression
52+ let codebook = buf. get ( 16 ..16 + 2048 ) . ok_or ( "not enough 16-bit VQ codebook data" ) ?;
53+ let indices = buf. get ( 16 + 2048 ..16 + 2048 + width * height / 4 ) . ok_or ( "not enough VQ index data" ) ?;
54+ let mut pixels = vec ! [ 0u8 ; width * height * 2 ] ;
55+ for block_y in 0 ..height / 2 {
56+ let twiddled_block_y = bit_twiddle ( block_y) ;
57+ for block_x in 0 ..width / 2 {
58+ let twiddled_block_idx = twiddled_block_y | bit_twiddle ( block_x) << 1 ;
59+ let codebook_pos = indices[ twiddled_block_idx] as usize * 8 ;
60+ let x = block_x * 2 ;
61+ let y = block_y * 2 ;
62+ pixels[ ( y * width + x) * 2 ] = codebook[ codebook_pos] ;
63+ pixels[ ( y * width + x) * 2 + 1 ] = codebook[ codebook_pos + 1 ] ;
64+ pixels[ ( y * width + x + 1 ) * 2 ] = codebook[ codebook_pos + 4 ] ;
65+ pixels[ ( y * width + x + 1 ) * 2 + 1 ] = codebook[ codebook_pos + 5 ] ;
66+ pixels[ ( ( y + 1 ) * width + x) * 2 ] = codebook[ codebook_pos + 2 ] ;
67+ pixels[ ( ( y + 1 ) * width + x) * 2 + 1 ] = codebook[ codebook_pos + 3 ] ;
68+ pixels[ ( ( y + 1 ) * width + x + 1 ) * 2 ] = codebook[ codebook_pos + 6 ] ;
69+ pixels[ ( ( y + 1 ) * width + x + 1 ) * 2 + 1 ] = codebook[ codebook_pos + 7 ] ;
70+ }
71+ }
72+ if pixel_fmt == 0 {
73+ Frame :: from_bgra5551 ( width as u32 , height as u32 , & pixels) . with_og_fmt ( PixelFormat :: Bgra5551Vq8 )
74+ } else if pixel_fmt == 1 {
75+ Frame :: from_bgr565 ( width as u32 , height as u32 , & pixels) . with_og_fmt ( PixelFormat :: Bgr565Vq8 )
76+ } else {
77+ Frame :: from_bgra4444 ( width as u32 , height as u32 , & pixels) . with_og_fmt ( PixelFormat :: Bgra4444Vq8 )
5678 }
57- }
58- if pixel_fmt == 0 {
59- Frame :: from_bgra5551 ( width as u32 , height as u32 , & pixels) . with_og_fmt ( PixelFormat :: Bgra5551Vq8 )
60- } else if pixel_fmt == 1 {
61- Frame :: from_bgr565 ( width as u32 , height as u32 , & pixels) . with_og_fmt ( PixelFormat :: Bgr565Vq8 )
6279 } else {
63- Frame :: from_bgra4444 ( width as u32 , height as u32 , & pixels) . with_og_fmt ( PixelFormat :: Bgra4444Vq8 )
80+ if pixel_fmt == 0 {
81+ Frame :: from_bgra5551 ( width as u32 , height as u32 , buf. get ( 16 ..16 + width * height * 2 ) . ok_or ( "not enough pixel data for BGRA5551" ) ?)
82+ } else if pixel_fmt == 1 {
83+ Frame :: from_bgr565 ( width as u32 , height as u32 , buf. get ( 16 ..16 + width * height * 2 ) . ok_or ( "not enough pixel data for BGR565" ) ?)
84+ } else {
85+ Frame :: from_bgra4444 ( width as u32 , height as u32 , buf. get ( 16 ..16 + width * height * 2 ) . ok_or ( "not enough pixel data for BGRA4444" ) ?)
86+ }
6487 }
65- } else {
66- if pixel_fmt == 0 {
67- Frame :: from_bgra5551 ( width as u32 , height as u32 , buf. get ( 16 ..16 + width * height * 2 ) . ok_or ( "not enough pixel data for BGRA5551" ) ?)
68- } else if pixel_fmt == 1 {
69- Frame :: from_bgr565 ( width as u32 , height as u32 , buf. get ( 16 ..16 + width * height * 2 ) . ok_or ( "not enough pixel data for BGR565" ) ?)
88+ }
89+ 5 => {
90+ if twiddle_type == 7 && palette_bytes. is_empty ( ) {
91+ return Err ( "file needs external palette, unimplemented" . into ( ) ) ;
92+ } else if palette_bytes. is_empty ( ) {
93+ Frame :: from_bgra_clut4 (
94+ width as u32 , height as u32 ,
95+ buf. get ( 16 ..16 + 1024 ) . ok_or ( "not enough palette data for BGRA clut4" ) ?,
96+ buf. get ( 16 + 1024 ..16 + 1024 + width * height / 2 ) . ok_or ( "not enough index data for BGRA clut4" ) ?
97+ )
7098 } else {
71- Frame :: from_bgra4444 ( width as u32 , height as u32 , buf. get ( 16 ..16 + width * height * 2 ) . ok_or ( "not enough pixel data for BGRA4444" ) ?)
99+ Frame :: from_bgra_clut4 (
100+ width as u32 , height as u32 ,
101+ & palette_bytes,
102+ buf. get ( 16 ..16 + width * height / 2 ) . ok_or ( "not enough data for BGRA clut4" ) ?
103+ )
72104 }
73105 }
74- }
75- 5 => {
76- if twiddle_type == 7 {
77- return Err ( "file needs external palette, unimplemented" . into ( ) ) ;
78- } else if palette_bytes. is_empty ( ) {
79- Frame :: from_bgra_clut4 (
80- width as u32 , height as u32 ,
81- buf. get ( 16 ..16 + 1024 ) . ok_or ( "not enough palette data for BGRA clut4" ) ?,
82- buf. get ( 16 + 1024 ..16 + 1024 + width * height / 2 ) . ok_or ( "not enough index data for BGRA clut4" ) ?
83- )
84- } else {
85- Frame :: from_bgra_clut4 (
86- width as u32 , height as u32 ,
87- & palette_bytes,
88- buf. get ( 16 ..16 + width * height / 2 ) . ok_or ( "not enough data for BGRA clut4" ) ?
89- )
90- }
91- }
92- 6 => {
93- if twiddle_type == 7 {
94- return Err ( "file needs external palette, unimplemented" . into ( ) ) ;
95- } else if palette_bytes. is_empty ( ) {
96- Frame :: from_bgra_clut8 (
97- width as u32 , height as u32 ,
98- buf. get ( 16 ..16 + 1024 ) . ok_or ( "not enough palette data for BGRA clut8" ) ?,
99- buf. get ( 16 + 1024 ..16 + 1024 + width * height) . ok_or ( "not enough index data for BGRA clut8" ) ?
100- )
101- } else {
102- Frame :: from_bgra_clut8 (
103- width as u32 , height as u32 ,
104- & palette_bytes,
105- buf. get ( 16 ..16 + width * height) . ok_or ( "not enough data for BGRA clut8" ) ?
106- )
106+ 6 => {
107+ if twiddle_type == 7 && palette_bytes. is_empty ( ) {
108+ return Err ( "file needs external palette, unimplemented" . into ( ) ) ;
109+ } else if palette_bytes. is_empty ( ) {
110+ Frame :: from_bgra_clut8 (
111+ width as u32 , height as u32 ,
112+ buf. get ( 16 ..16 + 1024 ) . ok_or ( "not enough palette data for BGRA clut8" ) ?,
113+ buf. get ( 16 + 1024 ..16 + 1024 + width * height) . ok_or ( "not enough index data for BGRA clut8" ) ?
114+ )
115+ } else {
116+ Frame :: from_bgra_clut8 (
117+ width as u32 , height as u32 ,
118+ & palette_bytes,
119+ buf. get ( 16 ..16 + width * height) . ok_or ( "not enough data for BGRA clut8" ) ?
120+ )
121+ }
107122 }
123+ _ => return Err ( format ! ( "unhandled PVR pixel format {pixel_fmt}" ) )
124+ } ;
125+ if [ 1 , 2 , 5 , 6 , 7 , 8 , 13 ] . contains ( & twiddle_type) {
126+ frame = frame. twiddled_dc ( ) ;
108127 }
109- _ => return Err ( format ! ( "unhandled PVR pixel format {pixel_fmt}" ) )
110- } ;
111- if [ 1 , 2 , 5 , 6 , 7 , 8 , 13 ] . contains ( & twiddle_type) {
112- frame = frame. twiddled_dc ( ) ;
128+ frames. push ( frame) ;
113129 }
114- Ok ( Image { frames : Box :: new ( [ frame ] ) } )
130+ Ok ( Image { frames : frames . into_boxed_slice ( ) } )
115131 }
116132} ;
0 commit comments