Merge branch 'master' into divVerent/skyboxes
[xonotic/xonotic-maps.pk3dir.git] / scripts / shader-audit.sh
1 #!/bin/sh
2
3 LF="
4 "
5
6 normalize()
7 {
8         echo "$1" | sed 's/\.\(tga\|jpg\|png\)$//'
9 }
10
11 allowed_prefixes=
12 forbidden_prefixes=
13
14 textures_used=
15 # $1 = shader
16 # $2 = texture
17 # $3 = shader | map | animmap | editorimage | sky
18 use_texture()
19 {
20         # does texture exist?
21         if \
22                 [ -f "../$2.tga" ] || \
23                 [ -f "../$2.jpg" ] || \
24                 [ -f "../$2.png" ]; then
25                 :
26         else
27                 if [ "$3" = "shader" ]; then
28                         return
29                 else
30                         echo "(EE) shader $1 uses non-existing texture $2"
31                 fi
32         fi
33         textures_used="$textures_used$LF$2"
34
35         if [ -n "$allowed_prefixes" ]; then
36                 ok=false
37                 for p in $allowed_prefixes; do
38                         case "$1:" in
39                                 "$p"*)
40                                         ok=true
41                                         ;;
42                         esac
43                 done
44         else
45                 ok=true
46         fi
47         for p in $forbidden_prefixes; do
48                 case "$1:" in
49                         "$p"*)
50                                 ok=false
51                                 ;;
52                 esac
53         done
54         if ! $ok; then
55                 echo "(EE) shader $1 is not allowed in this shader file (allowed: $allowed_prefixes, forbidden: $forbidden_prefixes)"
56         fi
57
58         case "$3" in
59                 ## RULE: skyboxes must lie in env/
60                 sky)
61                         case "$2" in
62                                 env/*)
63                                         ;;
64                                 *)
65                                         echo "(EE) texture $2 of shader $1 is out of place, $3 textures must be in env/"
66                                         ;;
67                         esac
68                         ;;
69                 ## RULE: non-skyboxes must not lie in env/
70                 *)
71                         case "$2" in
72                                 env/*)
73                                         echo "(EE) texture $2 of shader $1 is out of place, $3 textures must not be in env/"
74                                         ;;
75                                 *)
76                                         ;;
77                         esac
78                         ;;
79         esac
80
81         # verify shader -> texture name
82         case "$1" in
83                 ## RULE: textures/FOOx/BAR-BAZ must use textures/FOOx/*/*, recommended textures/FOOx/BAR/BAZ
84                 textures/*x/*-*)
85                         pre=${1%%x/*}x
86                         suf=${1#*x/}
87                         suf="`echo "$suf" | sed 's,-,/,g'`"
88                         case "$2" in
89                                 "$pre"/*/*)
90                                         ;;
91                                 *)
92                                         echo "(EE) texture $2 of shader $1 is out of place, recommended file name is $pre/$suf"
93                                         ;;
94                         esac
95                         ;;
96                 ## RULE: textures/FOOx/BAR must use textures/FOOx/*/*, recommended textures/FOOx/base/BAR
97                 textures/*x/*)
98                         pre=${1%%x/*}x
99                         suf=${1#*x/}
100                         case "$2" in
101                                 "$pre"/*/*)
102                                         ;;
103                                 *)
104                                         echo "(EE) texture $2 of shader $1 is out of place, recommended file name is $pre/base/$suf"
105                                         ;;
106                         esac
107                         ;;
108                 ## RULE: textures/map_FOO[_/]* must use textures/map_FOO[_/]*
109                 textures/map_*/*)
110                         pre=${1%%/map_*}
111                         suf=${1#*/map_}
112                         map=${suf%%[_/]*}
113                         case "$2" in
114                                 "$pre"/map_$map[/_]*)
115                                         ;;
116                                 textures/map_*)
117                                         # protect one map's textures from the evil of other maps :P
118                                         echo "(EE) texture $2 of shader $1 is out of place, recommended file name is $pre/map_$map/*"
119                                         ;;
120                                 *)
121                                         # using outside stuff is permitted
122                                         ;;
123                         esac
124                         ;;
125                 ## RULE: textures/common/FOO must use textures/common/FOO or textures/common/*/*
126                 textures/common/*)
127                         case "$2" in
128                                 "$1")
129                                         ;;
130                                 textures/common/*/*)
131                                         ;;
132                                 *)
133                                         echo "(EE) texture $2 of shader $1 is out of place, recommended file name is $1 or textures/common/*/*"
134                                         ;;
135                         esac
136                         ;;
137                 ## RULE: textures/FOO/* must use textures/FOO/*, for FOO in decals, liquids_water, liquids_slime, liquids_lava, warpzone
138                 textures/decals/*|textures/liquids_water/*|textures/liquids_slime/*|textures/liquids_lava/*|textures/warpzone/*)
139                         pre=${1%/*}
140                         case "$2" in
141                                 "$pre"/*)
142                                         # I _suppose_ this is fine, as tZork committed this pack
143                                         ;;
144                                 *)
145                                         echo "(EE) texture $2 of shader $1 is out of place, recommended file name is $1"
146                                         ;;
147                         esac
148                         ;;
149                 ## RULE: textures/skies/FOO or textures/skies/FOO_BAR must use textures/skies/FOO respective textures/skies/FOO_BAR as preview image, and env/FOO[_/]* as skybox
150                 textures/skies/*)
151                         sky=${1#textures/skies/}
152                         sky=${sky%%_*}
153                         case "$2" in
154                                 "$1")
155                                         # typical place for preview image
156                                         ;;
157                                 env/$sky[/_]*)
158                                         # typical place for skybox
159                                         ;;
160                                 *)
161                                         echo "(EE) texture $2 of shader $1 is out of place, recommended file name is $1"
162                                         ;;
163                         esac
164                         ;;
165                 ## RULE: models/* must use models/*
166                 models/*)
167                         case "$2" in
168                                 models/*)
169                                         ;;
170                                 *)
171                                         echo "(EE) texture $2 of shader $1 is out of place, recommended file name is $1 or models/*"
172                                         ;;
173                         esac
174                         ;;
175                 *)
176                         echo "(EE) no shader name pattern for $1"
177                         ;;
178         esac
179 }
180
181 parsing_shader=
182 parse_shaderstage()
183 {
184         while read L A1 A2 Aother; do
185                 case "$L" in
186                         map)
187                                 case "$A1" in
188                                         '$lightmap')
189                                                 ;;
190                                         *)
191                                                 use_texture "$parsing_shader" "`normalize "$A1"`" map
192                                                 ;;
193                                 esac
194                                 ;;
195                         animmap)
196                                 for X in $A2 $Aother; do
197                                         use_texture "$parsing_shader" "`normalize "$X"`" animmap
198                                 done
199                                 ;;
200                         '}')
201                                 break
202                                 ;;
203                         *)
204                                 ;;
205                 esac
206         done
207 }
208
209 parse_shader()
210 {
211         use_texture "$parsing_shader" "$parsing_shader" shader
212         while read L A1 AREST; do
213                 case "$L" in
214                         qer_editorimage)
215                                 use_texture "$parsing_shader" "`normalize "$A1"`" editorimage
216                                 ;;
217                         skyparms)
218                                 use_texture "$parsing_shader" "${A1}_lf" sky
219                                 use_texture "$parsing_shader" "${A1}_rt" sky
220                                 use_texture "$parsing_shader" "${A1}_up" sky
221                                 use_texture "$parsing_shader" "${A1}_dn" sky
222                                 use_texture "$parsing_shader" "${A1}_ft" sky
223                                 use_texture "$parsing_shader" "${A1}_bk" sky
224                                 ;;
225                         '{')
226                                 parse_shaderstage
227                                 ;;
228                         '}')
229                                 break
230                                 ;;
231                         *)
232                                 ;;
233                 esac
234         done
235 }
236
237 parse_shaderfile()
238 {
239         case "$1" in
240                 ## RULE: map_FOO.shader may define tetxures/map_FOO_* and textures/map_FOO/*
241                 map_*)
242                         allowed_prefixes="textures/map_`echo "$1" | cut -d _ -f 2`_ textures/map_`echo "$1" | cut -d - -f 2`/"
243                         forbidden_prefixes=
244                         ;;
245                 ## RULE: skies_FOO.shader may define tetxures/skies/FOO and textures/skies/FOO_*
246                 skies_*)
247                         allowed_prefixes="textures/skies/`echo "$1" | cut -d _ -f 2`: textures/skies/`echo "$1" | cut -d _ -f 2`_"
248                         forbidden_prefixes=
249                         ;;
250                 ## RULE: model_*.shader may define models/*
251                 model_*)
252                         allowed_prefixes="models/"
253                         forbidden_prefixes=
254                         ;;
255                 ## RULE: any other FOO.shader may define textures/FOO/*
256                 *)
257                         allowed_prefixes="textures/$1/"
258                         forbidden_prefixes="textures/skies/ textures/map_ models/"
259                         ;;
260         esac
261         while read L; do
262                 case "$L" in
263                         */*)
264                                 parsing_shader="`normalize "$L"`"
265                                 if [ x"$L" != x"$parsing_shader" ]; then
266                                         echo "(WW) normalized shader name $L to $parsing_shader"
267                                 fi
268                                 ;;
269                         '{')
270                                 parse_shader
271                                 ;;
272                         *)
273                                 ;;
274                 esac
275         done
276 }
277
278 strip_comments()
279 {
280         sed 's,//.*,,g; s,\r, ,g; s,\t, ,g; s,  *, ,g; s, $,,; s,^ ,,; /^$/ d'
281 }
282
283 t=`mktemp`
284 for X in *.shader; do
285         strip_comments < "$X" > "$t"
286         parse_shaderfile "${X%.shader}" < "$t"
287 done
288 rm -f "$t"
289
290 textures_avail=`( cd ..; find textures/ -type f -not -name '*_norm.*' -not -name '*_glow.*' -not -name '*_gloss.*' -not -name '*.xcf' ) | while IFS= read -r T; do normalize "$T"; done | sort -u`
291 textures_used=`echo "${textures_used#$LF}" | sort -u`
292
293 echo "$textures_used$LF$textures_used$LF$textures_avail" | sort | uniq -u | while IFS= read -r L; do
294         case "$L" in
295                 textures/radiant/*)
296                         ;;
297                 textures/map_*/*)
298                         ;;
299                 *)
300                         echo "(EE) texture $L is not referenced by any shader"
301                         ;;
302         esac
303 done