M => +68 -10
@@ 1,5 1,7 @@
#!/bin/env tclsh
#proc pvr2png
proc fatal {num reason} {
global argv0
puts stderr "fatal: $argv0: $reason"
@@ 17,31 19,87 @@ set fp [open $file rb]
binary scan [read $fp 0xc] {iii} magic numents startpos
if {$magic != 0x00434150} {
die 2 "unknown magic: $magic"
} else {
puts "magic = $magic, OK"
die 2 "${file}: unknown magic: [format %08x $magic]"
}
set hdrlen [expr {0xc + ($numents * 4)}]
puts "header length: $hdrlen ($numents entries)"
puts "data offset: $startpos"
puts "${file}: header length: $hdrlen ($numents entries)"
puts "${file}: record start: $startpos"
puts "reading end table..."
set endhdr [read $fp [expr {$numents * 4}]]
binary scan $endhdr "i$numents" endtab
puts $endtab
puts "${file}: record end table: $endtab"
seek $fp $startpos
file mkdir $dir
set pos $startpos
set i 0
foreach endpt $endtab {
set id [format %04d $i]
set filebase $dir/$id
set length [expr {$endpt - $pos}]
set data [read $fp $length]
set fp2 [open $dir/[format %08x $endpt].bin wb]
puts $fp2 $data
close $fp2
set type [string range $data 0 3]
switch -- $type {
NZIP {
puts "${file}: record $id: Deflate Compressed"
set data [string range $data 8 end]
set decom [zlib inflate $data]
set magic [string range $decom 0 3]
if {$magic in {GBIX PVRT}} {
set ext pvr
puts "${file}: record $id (decompressed): PVRT Image Data"
} else {
set ext bin
binary scan $type i tynum
puts "${file}: record $id (decompressed): Unknown (magic 0x[format %08x $tynum])"
}
set fp2 [open ${filebase}.${ext} wb]
puts $fp2 $decom
close $fp2
if {$ext == "pvr"} {
pvrt2tga::convert ${filebase}.${ext} ${filebase}.tga
exec -- convert ${filebase}.tga ${filebase}.png
file delete ${filebase}.tga
puts "${file}: record $id (decompressed): Converted to PNG"
}
}
NJCM {
puts "${file}: record $id: Ninja Chunk Model"
set fp2 [open ${filebase}.njcm wb]
puts $fp2 $data
close $fp2
}
NJTL {
puts "${file}: record $id: Ninja Texture List"
puts "${filebase}.njcm"
set fp2 [open ${filebase}.njtl wb]
puts $fp2 $data
close $fp2
}
NMDM {
puts "${file}: record $id: Ninja Motion"
set fp2 [open ${filebase}.nmdm wb]
puts $fp2 $data
close $fp2
}
default {
binary scan $type i tynum
puts "${file}: record $id: Unknown (magic 0x[format %08x $tynum])"
set fp2 [open ${filebase}.rec wb]
puts $fp2 $data
close $fp2
}
}
set pos $endpt
incr i
}
A pvrt.tcl => pvrt.tcl +246 -0
@@ 0,0 1,246 @@
+proc bindex {buf idx} {
+ binary scan $buf x${idx}c byte
+ expr {$byte & 0xff}
+}
+
+namespace eval ::pvrt2tga {}
+namespace eval ::pvrt2tga::pfmt {}
+namespace eval ::pvrt2tga::dfmt {
+ variable tmap {0 1}
+}
+
+# src = raw buffer, dst = []BGRA
+proc ::pvrt2tga::pfmt::lookup {code} {
+ switch -- $code {
+ 0 { return ::pvrt2tga::pfmt::argb1555 }
+ 1 { return ::pvrt2tga::pfmt::rgb565 }
+ 2 { return ::pvrt2tga::pfmt::argb4444 }
+ default { return "" }
+ }
+}
+proc ::pvrt2tga::pfmt::argb1555 {srcvar srcidx dstvar dstidx} {
+ upvar $srcvar srcbuf $dstvar dstbuf
+
+ set srcidx [expr {$srcidx * 2}]
+ binary scan $srcbuf x${srcidx}s pixel
+
+ set dstidx [expr {$dstidx * 4}]
+ lset dstbuf $dstidx+0 [expr {($pixel & 0x1f) * 0xff / 0x1f}]
+ lset dstbuf $dstidx+1 [expr {($pixel >> 0x5 & 0x1f) * 0xff / 0x1f}]
+ lset dstbuf $dstidx+2 [expr {($pixel >> 0xa & 0x1f) * 0xff / 0x1f}]
+ lset dstbuf $dstidx+3 [expr {($pixel >> 0xf & 0x01) * 0xff }]
+}
+proc ::pvrt2tga::pfmt::rgb565 {srcvar srcidx dstvar dstidx} {
+ upvar $srcvar srcbuf $dstvar dstbuf
+
+ set srcidx [expr {$srcidx * 2}]
+ binary scan $srcbuf x${srcidx}s pixel
+
+ set dstidx [expr {$dstidx * 4}]
+ lset dstbuf $dstidx+0 [expr {($pixel & 0x1f) * 0xff / 0x1f}]
+ lset dstbuf $dstidx+1 [expr {($pixel >> 0x5 & 0x3f) * 0xff / 0x3f}]
+ lset dstbuf $dstidx+2 [expr {($pixel >> 0xb & 0x1f) * 0xff / 0x1f}]
+ lset dstbuf $dstidx+3 255
+}
+proc ::pvrt2tga::pfmt::argb4444 {srcvar srcidx dstvar dstidx} {
+ upvar $srcvar srcbuf $dstvar dstbuf
+
+ set srcidx [expr {$srcidx * 2}]
+ binary scan $srcbuf x${srcidx}s pixel
+
+ set dstidx [expr {$dstidx * 4}]
+ lset dstbuf $dstidx+0 [expr {($pixel & 0xf) * 0x11}]
+ lset dstbuf $dstidx+1 [expr {($pixel >> 0x4 & 0xf) * 0x11}]
+ lset dstbuf $dstidx+2 [expr {($pixel >> 0x8 & 0xf) * 0x11}]
+ lset dstbuf $dstidx+3 [expr {($pixel >> 0xc & 0xf) * 0x11}]
+}
+
+proc ::pvrt2tga::dfmt::extend_tmap {len} {
+ variable tmap
+ for {set i [llength $tmap]} {$i < $len} {incr i} {
+ lappend tmap [expr {(([lindex $tmap $i-1] | 0xaaaaaaaa) + 1) & 0x55555555}]
+ }
+}
+
+# src = raw buffer, dst = []BGRA
+proc ::pvrt2tga::dfmt::lookup {code} {
+ switch -- $code {
+ 1 { return ::pvrt2tga::dfmt::square_twid }
+ 3 { return ::pvrt2tga::dfmt::vq }
+ 4 { return ::pvrt2tga::dfmt::vq_mipmap }
+ 9 { return ::pvrt2tga::dfmt::rect }
+ 13 { return ::pvrt2tga::dfmt::rect_twid }
+ 16 { return ::pvrt2tga::dfmt::small_vq }
+ default { return "" }
+ }
+}
+proc ::pvrt2tga::dfmt::square_twid {pfmt srcvar dstvar w h} {
+ variable tmap
+ upvar $srcvar srcbuf $dstvar dstbuf
+
+ extend_tmap $w
+
+ set dstidx 0
+ for {set y 0} {$y < $h} {incr y} {
+ for {set x 0} {$x < $w} {incr x} {
+ set srcidx [expr {[lindex $tmap $x] << 1 | [lindex $tmap $y]}]
+ $pfmt srcbuf $srcidx dstbuf $dstidx
+ incr dstidx
+ }
+ }
+}
+proc ::pvrt2tga::dfmt::vq {pfmt srcvar dstvar w h {mipmaps 0} {small 0}} {
+ variable tmap
+ upvar $srcvar srcbuf $dstvar dstbuf
+
+ extend_tmap $w
+
+ if {$small} {
+ if {$w <= 16} {
+ set pallen 64
+ } elseif {$w <= 32} {
+ set pallen 128
+ } elseif {$w <= 64} {
+ set pallen 512
+ } else {
+ set pallen 1024
+ }
+ } else {
+ set pallen 1024
+ }
+
+ set palbuf [lrepeat [expr {$pallen * 4}] 0]
+ for {set i 0} {$i < $pallen} {incr i} {
+ $pfmt srcbuf $i palbuf $i
+ }
+ set srcbuf [string range $srcbuf [expr {$pallen * 2}] end]
+
+ if {$mipmaps} {
+ set w2 [expr {int(pow(2, int(log($w) / log(2))))}]
+ set mipmaplen [lindex $tmap [expr {($w2 >> 1) - 1}]]
+ set srcbuf [string range $srcbuf $mipmaplen+1 end]
+ }
+
+ set dstidx 0
+ for {set y 0} {$y < $h / 2} {incr y} {
+ for {set x 0} {$x < $w / 2} {incr x} {
+ set srcidx [expr {[lindex $tmap $x] << 1 | [lindex $tmap $y]}]
+ set palidx [expr {[bindex $srcbuf $srcidx] * 16}]
+
+ for {set x2 0} {$x2 < 2} {incr x2} {
+ for {set y2 0} {$y2 < 2} {incr y2} {
+ set dstidx [expr {(($y * 2 + $y2) * $w + ($x * 2) + $x2) * 4}]
+
+ # puts "$w $h $pallen $palidx [llength $dstbuf] $dstidx"
+
+ lset dstbuf $dstidx+0 [lindex $palbuf $palidx+0]
+ lset dstbuf $dstidx+1 [lindex $palbuf $palidx+1]
+ lset dstbuf $dstidx+2 [lindex $palbuf $palidx+2]
+ lset dstbuf $dstidx+3 [lindex $palbuf $palidx+3]
+
+ incr palidx 4
+ }
+ }
+ }
+ }
+}
+proc ::pvrt2tga::dfmt::vq_mipmap {pfmt srcvar dstvar w h} {
+ upvar $srcvar srcbuf $dstvar dstbuf
+ vq $pfmt srcbuf dstbuf $w $h 1
+
+}
+proc ::pvrt2tga::dfmt::small_vq {pfmt srcvar dstvar w h} {
+ upvar $srcvar srcbuf $dstvar dstbuf
+ vq $pfmt srcbuf dstbuf $w $h 0 1
+
+}
+proc ::pvrt2tga::dfmt::rect {pfmt srcvar dstvar w h} {
+ variable tmap
+ upvar $srcvar srcbuf $dstvar dstbuf
+
+ extend_tmap $w
+
+ set i 0
+ for {set y 0} {$y < $h} {incr y} {
+ for {set x 0} {$x < $w} {incr x} {
+ $pfmt srcbuf $i dstbuf $i
+ incr i
+ }
+ }
+}
+proc ::pvrt2tga::dfmt::rect_twid {pfmt srcvar dstvar w h} {
+ variable tmap
+ upvar $srcvar srcbuf $dstvar dstbuf
+
+ set size [expr {min($w, $h)}]
+ extend_tmap $size
+
+ set nblk [expr {($w / $size) * ($h / $size)}]
+
+ set dstidx 0
+ for {set blk 0} {$blk < $nblk} {incr blk} {
+ if {$size != $w} {
+ set dstidx [expr {$blk * $size}]
+ }
+
+ for {set y 0} {$y < $size} {incr y} {
+ for {set x 0} {$x < $size} {incr x} {
+ set srcidx [expr {($size*$size*$blk) + ([lindex $tmap $x] << 1 | [lindex $tmap $y])}]
+ $pfmt srcbuf $srcidx dstbuf $dstidx
+ incr dstidx
+ }
+ if {$size != $w} {
+ incr dstidx [expr {$size * ($nblk - 1)}]
+ }
+ }
+ }
+}
+
+
+proc ::pvrt2tga::convert {src dst} {
+ set sfp [open $src rb]
+
+ if {[read $sfp 4] == "GBIX"} {
+ seek $sfp 16
+ }
+ if {[read $sfp 4] != "PVRT"} {
+ puts "$src not PVRT"
+ close $sfp
+ return
+ }
+
+ binary scan [read $sfp 12] iccsss len pfmt dfmt _ w h
+ set srcbuf [read $sfp [expr {$len - 8}]]
+ set dstbuf [lrepeat [expr {$w * $h * 4}] 0]
+
+ if {$dfmt != 4} {
+ close $sfp
+ return
+ }
+
+ set pdec [pfmt::lookup $pfmt]
+ set ddec [dfmt::lookup $dfmt]
+
+ puts "$src $dst $pdec $ddec $w $h"
+
+ $ddec $pdec srcbuf dstbuf $w $h
+
+ set tga [binary format cccsscsssscbc* 0 0 2 0 0 0 0 0 $w $h 32 00100000 $dstbuf]
+ set dfp [open $dst wb]
+ puts $dfp $tga
+ close $dfp
+
+ close $sfp
+}
+
+# pvrt2tga::convert ./unpacs/GAME/NOWLOAD/0000.pvr ./unpacs/GAME/NOWLOAD/0000.tga
+
+set dirs .
+while {$dirs != ""} {
+ set dirs [lassign $dirs dir]
+ set dirs [concat $dirs [glob -nocomplain -directory $dir */]]
+
+ foreach file [glob -nocomplain -directory $dir *.pvr] {
+ pvrt2tga::convert $file [file rootname $file].tga
+ }
+}