minimap support to nexuiz-map-compiler
[divverent/nexuiz.git] / misc / tools / nexuiz-map-compiler
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5 use POSIX;
6 use File::Temp;
7
8 # change these to match your system, or define them in ~/.nexuiz-map-compiler
9 # (just copy paste this part to the file ~/.nexuiz-map-compiler)
10
11         # Path to Nexuiz (where the data directory is in)
12         our $NEXUIZDIR   = '/home/polzer/Nexvn/nexuiz';
13
14         # Path to your q3map2 program. You find it in your GtkRadiant/install
15         # directory.
16         our $Q3MAP2      = '/home/users4/ommz/polzer/bin/q3map2.x86';
17
18         # General flags for q3map2 (for example -threads 4)
19         our $Q3MAP2FLAGS = '';
20
21         # Default flags for the -bsp stage
22         our $BSPFLAGS    = '-samplesize 8 -minsamplesize 4 -mv 1000000 -mi 6000000';
23
24         # Default flags for the -vis stage
25         our $VISFLAGS    = '';
26
27         # Default flags for the -light stage
28         our $LIGHTFLAGS  = '-deluxe -patchshadows -samples 3 -lightmapsize 512 -bounce 8 -fastbounce -bouncegrid';
29
30         # Default flags for the -minimap stage
31         our $MINIMAPFLAGS = '';
32
33 # end of user changable part
34
35 do "$ENV{HOME}/.nexuiz-map-compiler";
36
37 sub Usage()
38 {
39         print <<EOF;
40 Usage:
41 $0 mapname [-bsp bspflags...] [-vis visflags...] [-light lightflags...]
42 EOF
43         exit 1;
44 }
45
46 my $options =
47 {
48         bsp => [split /\s+/, $BSPFLAGS],
49         vis => [split /\s+/, $VISFLAGS],
50         light => [split /\s+/, $LIGHTFLAGS],
51         minimap => [split /\s+/, $MINIMAPFLAGS],
52         maps => [],
53         scale => 1
54 };
55
56 my $curmode = 'maps';
57
58 while(@ARGV)
59 {
60         $_ = shift @ARGV;
61         my $enterflags = undef;
62         if($_ eq '-bsp' or $_ eq '-meta')
63         {
64                 $enterflags = 'bsp';
65         }
66         elsif($_ eq '-vis')
67         {
68                 $enterflags = 'vis';
69         }
70         elsif($_ eq '-light')
71         {
72                 $enterflags = 'light';
73         }
74         elsif($_ eq '-minimap')
75         {
76                 $enterflags = 'minimap';
77         }
78         elsif($_ eq '-map')
79         {
80                 $curmode = 'maps';
81         }
82         elsif($_ eq '-scale')
83         {
84                 $options->{scale} = (shift @ARGV) || 1;
85         }
86         elsif($_ eq '-novis')
87         {
88                 $options->{vis} = undef;
89         }
90         elsif($_ eq '-nolight')
91         {
92                 $options->{light} = undef;
93         }
94         elsif($_ eq '-nominimap')
95         {
96                 $options->{minimap} = undef;
97         }
98         elsif($_ =~ /^-(-.*)/)
99         {
100                 if($curmode eq 'maps')
101                 {
102                         $curmode = 'bsp';
103                 }
104                 push @{$options->{$curmode}}, $1;
105         }
106         elsif($_ =~ /^-/ and $curmode eq 'maps')
107         {
108                 $curmode = 'bsp';
109                 push @{$options->{$curmode}}, $_;
110         }
111         else
112         {
113                 push @{$options->{$curmode}}, $_;
114         }
115         if(defined $enterflags)
116         {
117                 $curmode = $enterflags;
118                 if($ARGV[0] eq '+')
119                 {
120                         shift @ARGV;
121                 }
122                 else
123                 {
124                         $options->{$curmode} = [];
125                 }
126         }
127 }
128
129 my $linkdir = File::Temp::tempdir("nexuiz-map-compiler.XXXXXX", TMPDIR => 1, CLEANUP => 1);
130
131 sub q3map2(@)
132 {
133         my @args = ($Q3MAP2, split(/\s+/, $Q3MAP2FLAGS), '-game', 'nexuiz', '-fs_basepath', $NEXUIZDIR, '-fs_basepath', $linkdir, '-v', @_);
134         print "\$ @args\n";
135         return !system @args;
136 }
137
138 (my $mapdir = getcwd()) =~ s!/[^/]*(?:$)!!;
139 $mapdir = "/" if $mapdir eq "";
140 symlink "$mapdir", "$linkdir/data";
141
142 my ($prescale, $postscale) = ($options->{scale} =~ /^([0-9.]+)(?::([0-9.]+))?$/);
143 $postscale = 1 if not defined $postscale;
144
145 for my $m(@{$options->{maps}})
146 {
147         $m =~ s/\.(?:map|bsp)$//;
148         if($prescale != 1 or $postscale != 1)
149         {
150                 open my $checkfh, "<", "$m.map"
151                         or die "open $m.map: $!";
152                 my $keeplights = 0;
153                 while(<$checkfh>)
154                 {
155                         /^\s*"_keeplights"\s+"1"\s*$/
156                                 or next;
157                         $keeplights = 1;
158                 }
159                 close $checkfh;
160                 die "$m does not define _keeplights to 1"
161                         unless $keeplights;
162         }
163
164         my %shaders = map { m!/([^/.]*)\.shader(?:$)! ? ($1 => 1) : () } glob "../scripts/*.shader";
165
166         my $previous_shaderlist = undef;
167         my $shaderlist = "";
168         if(open my $fh, "<", "$NEXUIZDIR/scripts/shaderlist.txt")
169         {
170                 while(<$fh>)
171                 {
172                         $shaderlist .= $_;
173                 }
174
175                 # we may have to restore the file on exit
176                 $previous_shaderlist = $shaderlist
177                         if "$NEXUIZDIR/data" eq $mapdir;
178         }
179         else
180         {
181                 # possibly extract the shader list from a pk3?
182                 local $ENV{N} = $NEXUIZDIR;
183                 $shaderlist = `cd "\$N" && for X in "\$N"/data/data*.pk3; do Y=\$X; done; unzip -p "\$Y" scripts/shaderlist.txt`;
184         }
185
186         my $shaderlist_new = "";
187         for(split /\r?\n|\r/, $shaderlist)
188         {
189                 delete $shaders{$_};
190                 $shaderlist_new .= "$_\n";
191         }
192         if(%shaders)
193         {
194                 for(sort keys %shaders)
195                 {
196                         $shaderlist_new .= "$_\n";
197                 }
198         }
199         else
200         {
201                 $shaderlist_new = undef;
202         }
203
204         my $restore_shaderlist = sub
205         {
206                 if(defined $shaderlist_new)
207                 {
208                         if(defined $previous_shaderlist)
209                         {
210                                 open my $fh, ">", "$mapdir/scripts/shaderlist.txt";
211                                 print $fh $previous_shaderlist;
212                                 close $fh;
213                         }
214                         else
215                         {
216                                 unlink "$mapdir/scripts/shaderlist.txt";
217                         }
218                 }
219         };
220         local $SIG{INT} = sub
221         {
222                 print "SIGINT caught, cleaning up...\n";
223                 $restore_shaderlist->();
224                 exit 0;
225         };
226
227         eval
228         {
229                 if(defined $shaderlist_new)
230                 {
231                         mkdir "$mapdir/scripts";
232                         open my $fh, ">", "$mapdir/scripts/shaderlist.txt";
233                         print $fh $shaderlist_new;
234                         close $fh;
235                 }
236
237                 unlink <$m/lm_*>; # delete old external lightmaps
238                 q3map2 '-bsp', '-meta', @{$options->{bsp}},   "$m.map"
239                         or die "-bsp: $?";
240                 if($prescale != 1)
241                 {
242                         q3map2 '-scale', $prescale, "$m.bsp"
243                                 or die "-scale: $?";
244                         rename "${m}_s.bsp", "$m.bsp"
245                                 or die "rename ${m}_s.bsp $m.bsp: $!";
246                 }
247                 if(defined $options->{light})
248                 {
249                         q3map2 '-light',        @{$options->{light}}, "$m.map"
250                                 or die "-light: $?";
251                 }
252                 if(defined $options->{vis})
253                 {
254                         q3map2 '-vis',          @{$options->{vis}},   "$m.map"
255                                 or die "-vis: $?";
256                 }
257                 if($postscale != 1)
258                 {
259                         q3map2 '-scale', $postscale, "$m.bsp"
260                                 or die "-scale: $?";
261                         rename "${m}_s.bsp", "$m.bsp"
262                                 or die "rename ${m}_s.bsp $m.bsp: $!";
263                 }
264                 if(defined $options->{minimap})
265                 {
266                         q3map2 '-minimap',      @{$options->{minimap}}, "$m.map"
267                                 or die "-minimap: $?";
268                 }
269
270                 unlink "$m.srf";
271
272                 $restore_shaderlist->();
273                 1;
274         }
275         or do
276         {
277                 $restore_shaderlist->();
278                 die $@;
279         };
280 }