~aleteoryx/mtg-pac

ref: 0fd560cb0fcf9d7f69b026999cb22a17b683afd0 mtg-pac/pvrt.tcl -rw-r--r-- 5.8 KiB
0fd560cb — Aleteoryx damn thing works 3 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
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]

	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
}