]> git.xonotic.org Git - xonotic/xonotic.git/blob - misc/tools/cached-converter.sh
allow the tempdir to be a hardlink structure (i.e. don't change files in there, alway...
[xonotic/xonotic.git] / misc / tools / cached-converter.sh
1 #!/bin/sh
2
3 set -e
4
5 : ${CACHEDIR:=$HOME/.xonotic-cached-converter}
6 : ${do_jpeg:=true}
7 : ${do_jpeg_if_not_dds:=false}
8 : ${jpeg_qual_rgb:=95}
9 : ${jpeg_qual_a:=99}
10 : ${do_dds:=true}
11 : ${dds_tool:=compressonator-dxtc}
12 : ${do_ogg:=false}
13 : ${ogg_qual:=1}
14 : ${del_src:=false}
15 : ${git_src_repo:=}
16
17 me=$0
18 case "$me" in
19         */*)
20                 meprefix=${me%/*}/
21                 ;;
22         *)
23                 meprefix=
24                 ;;
25 esac
26
27 tmpdir=`mktemp -d -t cached-converter.XXXXXX`
28 trap 'exit 1' INT
29 trap 'rm -rf "$tmpdir"' EXIT
30
31 lastinfiles=
32 lastinfileshash=
33 cached()
34 {
35         flag=$1; shift
36         method=$1; shift
37         infile1=$1; shift
38         infile2=$1; shift
39         outfile1=$1; shift
40         outfile2=$1; shift
41         if ! $flag; then
42                 return 0
43         fi
44         #sleep 0.25
45         if [ x"$infile1" = x"$outfile1" ]; then
46                 keep=true
47         fi
48         options=`echo "$*" | git hash-object --stdin`
49         if [ x"$infile1/../$infile2" = x"$lastinfiles" ]; then
50                 sum=$lastinfileshash
51         else
52                 evil=false
53                 for infile in "$infile1" "$infile2"; do
54                         case "$infile" in
55                                 */background_l2.tga)
56                                         evil=true
57                                         ;;
58                         esac
59                 done
60                 if [ -n "$git_src_repo" ] && ! $evil; then
61                         sum=`( cd "$git_src_repo"; git rev-parse --revs-only HEAD:"${infile1#./}" | grep . ) || git hash-object "$infile1"`
62                         if [ -n "$infile2" ]; then
63                                 sum=$sum`( cd "$git_src_repo"; git rev-parse --revs-only HEAD:"${infile2#./}" | grep . ) || git hash-object "$infile2"`
64                         fi
65                 else
66                         sum=`git hash-object "$infile1"`
67                         if [ -n "$infile2" ]; then
68                                 sum=$sum`git hash-object "$infile2"`
69                         fi
70                 fi
71                 lastinfileshash=$sum
72         fi
73         mkdir -p "$CACHEDIR/$method-$options"
74         name1="$CACHEDIR/$method-$options/$sum-1.${outfile1##*.}"
75         [ -z "$outfile2" ] || name2="$CACHEDIR/$method-$options/$sum-2.${outfile2##*.}"
76         tempfile1="${name1%/*}/new-${name1##*/}"
77         [ -z "$outfile2" ] || tempfile2="${name2%/*}/new-${name2##*/}"
78         if [ -f "$name1" ] && { [ -z "$outfile2" ] || [ -f "$name2" ]; }; then
79                 case "$outfile1" in */*) mkdir -p "${outfile1%/*}"; esac && { ln -f "$name1" "$outfile1" 2>/dev/null || { rm -f "$outfile1" && cp "$name1" "$outfile1"; }; }
80                 [ -z "$outfile2" ] || { case "$outfile2" in */*) mkdir -p "${outfile2%/*}"; esac && { ln -f "$name2" "$outfile2" 2>/dev/null || { rm -f "$outfile2" && cp "$name2" "$outfile2"; }; }; }
81                 conv=true
82         elif "$method" "$infile1" "$infile2" "$tempfile1" "$tempfile2" "$@"; then
83                 mv "$tempfile1" "$name1"
84                 [ -z "$outfile2" ] || mv "$tempfile2" "$name2"
85                 case "$outfile1" in */*) mkdir -p "${outfile1%/*}"; esac && { ln -f "$name1" "$outfile1" 2>/dev/null || { rm -f "$outfile1" && cp "$name1" "$outfile1"; }; }
86                 [ -z "$outfile2" ] || { case "$outfile2" in */*) mkdir -p "${outfile2%/*}"; esac && { ln -f "$name2" "$outfile2" 2>/dev/null || { rm -f "$outfile2" && cp "$name2" "$outfile2"; }; }; }
87                 conv=true
88         else
89                 rm -f "$tempfile1"
90                 rm -f "$tempfile2"
91                 exit 1
92         fi
93 }
94
95 reduce_jpeg2_dds()
96 {
97         i=$1; shift
98         ia=$1; shift
99         o=$1; shift; shift 
100         convert "$i" "$ia" -compose CopyOpacity -composite "$tmpdir/x.tga" && \
101         "$meprefix"compress-texture "$dds_tool" dxt5 "$tmpdir/x.tga" "$o" $1
102 }
103
104 reduce_jpeg2_dds_premul()
105 {
106         i=$1; shift
107         ia=$1; shift
108         o=$1; shift; shift 
109         convert "$i" "$ia" -compose CopyOpacity -composite "$tmpdir/x.tga" && \
110         "$meprefix"compress-texture "$dds_tool" dxt4 "$tmpdir/x.tga" "$o" $1
111 }
112
113 reduce_jpeg2_jpeg2()
114 {
115         i=$1; shift
116         ia=$1; shift
117         o=$1; shift
118         oa=$1; shift
119         if convert "$i" TGA:- | cjpeg -targa -quality "$1" -optimize -sample 1x1,1x1,1x1 > "$o"; then
120                 if [ "`stat -c %s "$i"`" -lt "`stat -c %s "$o"`" ]; then
121                         cp "$i" "$o"
122                 fi
123         else
124                 return 1
125         fi
126         if convert "$ia" TGA:- | cjpeg -targa -quality "$2" -optimize -sample 1x1,1x1,1x1 > "$oa"; then
127                 if [ "`stat -c %s "$ia"`" -lt "`stat -c %s "$oa"`" ]; then
128                         cp "$ia" "$oa"
129                 fi
130         else
131                 return 1
132         fi
133 }
134
135 reduce_jpeg_jpeg()
136 {
137         i=$1; shift; shift
138         o=$1; shift; shift
139         if convert "$i" TGA:- | cjpeg -targa -quality "$1" -optimize -sample 1x1,1x1,1x1 > "$o"; then
140                 if [ "`stat -c %s "$i"`" -lt "`stat -c %s "$o"`" ]; then
141                         cp "$i" "$o"
142                 fi
143         else
144                 return 1
145         fi
146 }
147
148 reduce_ogg_ogg()
149 {
150         i=$1; shift; shift
151         o=$1; shift; shift
152         tags=`vorbiscomment -R -l "$i" || true`
153         oggdec -o "$tmpdir/x.wav" "$i" && \
154         oggenc -q"$1" -o "$o" "$tmpdir/x.wav"
155         echo "$tags" | vorbiscomment -R -w "$o" || true
156 }
157
158 reduce_wav_ogg()
159 {
160         i=$1; shift; shift
161         o=$1; shift; shift
162         oggenc -q"$1" -o "$o" "$i"
163 }
164
165 reduce_rgba_dds()
166 {
167         i=$1; shift; shift
168         o=$1; shift; shift
169         convert "$i" "$tmpdir/x.tga" && \
170         "$meprefix"compress-texture "$dds_tool" dxt5 "$tmpdir/x.tga" "$o" $1
171 }
172
173 reduce_rgba_dds_premul()
174 {
175         i=$1; shift; shift
176         o=$1; shift; shift
177         convert "$i" "$tmpdir/x.tga" && \
178         "$meprefix"compress-texture "$dds_tool" dxt4 "$tmpdir/x.tga" "$o" $1
179 }
180
181 reduce_rgba_jpeg2()
182 {
183         i=$1; shift; shift
184         o=$1; shift
185         oa=$1; shift
186         if convert "$i" -alpha off TGA:- | cjpeg -targa -quality "$1" -optimize -sample 1x1,1x1,1x1 > "$o"; then
187                 :
188         else
189                 return 1
190         fi
191         if convert "$i" -alpha extract TGA:- | cjpeg -targa -quality "$2" -optimize -sample 1x1,1x1,1x1 > "$oa"; then
192                 :
193         else
194                 return 1
195         fi
196 }
197
198 reduce_rgb_dds()
199 {
200         i=$1; shift; shift
201         o=$1; shift; shift
202         convert "$i" "$tmpdir/x.tga" && \
203         "$meprefix"compress-texture "$dds_tool" dxt1 "$tmpdir/x.tga" "$o" $1
204 }
205
206 reduce_rgb_jpeg()
207 {
208         i=$1; shift; shift
209         o=$1; shift; shift
210         if convert "$i" TGA:- | cjpeg -targa -quality "$1" -optimize -sample 1x1,1x1,1x1 > "$o"; then
211                 :
212         else
213                 return 1
214         fi
215 }
216
217 has_alpha()
218 {
219         i=$1; shift; shift
220         o=$1; shift; shift
221         if convert "$i" -depth 16 RGBA:- | perl -e 'while(read STDIN, $_, 8) { substr($_, 6, 2) eq "\xFF\xFF" or exit 1; } exit 0;'; then
222                 # no alpha
223                 : > "$o"
224         else
225                 # has alpha
226                 echo yes > "$o"
227         fi
228 }
229
230 to_delete=
231 for F in "$@"; do
232         f=${F%.*}
233
234         echo >&2 "Handling $F..."
235         conv=false
236         keep=false
237         jqual_rgb=$jpeg_qual_rgb
238         jqual_a=$jpeg_qual_a
239
240         will_jpeg=$do_jpeg
241         will_dds=$do_dds
242         case "$f" in
243                 *_bump) will_dds=false ;;
244                 ./models/player/*) will_dds=false ;;
245                 ./models/sprites/*) will_dds=false ;;
246                 ./textures/*) ;;
247                 ./models/*) ;;
248                 ./particles/*) ;;
249                 ./progs/*) ;;
250                 *)
251                         # we can't DDS compress the 2D textures, sorry
252                         # but JPEG is still fine
253                         will_dds=false
254                         ;;
255         esac
256
257         # for deluxemaps, lightmaps and normalmaps, enforce high jpeg quality (like on alpha channels)
258         if [ "$jqual_a" -gt "$jqual_rgb" ]; then
259                 case "$f" in
260                         ./maps/*/lm_[0-9][0-9][0-9][13579]) # deluxemap
261                                 jqual_rgb=$jqual_a
262                                 ;;
263                         ./maps/*/lm_[0-9][0-9][0-9][02468]) # lightmap
264                                 jqual_rgb=$jqual_a
265                                 ;;
266                         *_norm) # normalmap
267                                 jqual_rgb=$jqual_a
268                                 ;;
269                 esac
270         fi
271
272         pm=
273         case "$f" in
274                 ./particles/particlefont) # particlefont uses premultiplied alpha
275                         pm=_premul
276                         ;;
277         esac
278
279         if $do_jpeg_if_not_dds; then
280                 if $will_dds; then
281                         will_jpeg=false
282                 else
283                         will_jpeg=true
284                 fi
285         fi
286
287         case "$F" in
288                 *_alpha.jpg)
289                         # handle in *.jpg case
290
291                         # they always got converted, I assume
292                         if $will_dds || $will_jpeg; then
293                                 conv=true
294                         fi
295                         keep=$will_jpeg
296                         ;;
297                 *.jpg)
298                         if [ -f "${f}_alpha.jpg" ]; then
299                                 cached "$will_dds"  reduce_jpeg2_dds$pm "$F" "${f}_alpha.jpg" "dds/${f}.dds" ""               "$dds_flags"
300                                 cached "$will_jpeg" reduce_jpeg2_jpeg2  "$F" "${f}_alpha.jpg" "$F"           "${f}_alpha.jpg" "$jqual_rgb" "$jqual_a"
301                         else                                   
302                                 cached "$will_dds"  reduce_rgb_dds      "$F" ""               "dds/${f}.dds" ""               "$dds_flags"
303                                 cached "$will_jpeg" reduce_jpeg_jpeg    "$F" ""               "$F"           ""               "$jqual_rgb"
304                         fi
305                         ;;
306                 *.png|*.tga)
307                         cached true has_alpha "$F" "" "$F.hasalpha" ""
308                         conv=false
309                         if [ -s "$F.hasalpha" ]; then
310                                 cached "$will_dds"  reduce_rgba_dds$pm  "$F" ""               "dds/${f}.dds" ""               "$dds_flags"
311                                 cached "$will_jpeg" reduce_rgba_jpeg2   "$F" ""               "${f}.jpg"     "${f}_alpha.jpg" "$jqual_rgb" "$jqual_a"
312                         else                                                             
313                                 cached "$will_dds"  reduce_rgb_dds      "$F" ""               "dds/${f}.dds" ""               "$dds_flags"
314                                 cached "$will_jpeg" reduce_rgb_jpeg     "$F" ""               "${f}.jpg"     ""               "$jqual_rgb"
315                         fi
316                         rm -f "$F.hasalpha"
317                         ;;
318                 *.ogg)
319                         cached "$do_ogg" reduce_ogg_ogg "$F" "" "$F" "" "$ogg_qual"
320                         ;;
321                 ./sound/misc/null.wav)
322                         # never convert this one
323                         ;;
324                 *.wav)
325                         cached "$do_ogg" reduce_wav_ogg "$F" "" "${f}.ogg" "" "$ogg_qual"
326                         ;;
327         esac
328         if $del_src; then
329                 if $conv; then
330                         if ! $keep; then
331                                 # FIXME can't have spaces in filenames that way
332                                 to_delete="$to_delete $F"
333                         fi
334                 fi
335         fi
336         # fix up DDS paths by a symbolic link
337         if [ -f "dds/${f}.dds" ]; then
338                 if [ -z "${f##./textures/*}" ]; then
339                         if [ -n "${f##./textures/*/*}" ]; then
340                                 ln -snf "textures/${f#./textures/}.dds" "dds/${f#./textures/}.dds"
341                         fi
342                 fi
343         fi
344 done
345 for F in $to_delete; do
346         rm -f "$F"
347 done