]> git.xonotic.org Git - xonotic/xonotic.git/blob - misc/tools/xonotic-map-compiler
remove .x86 suffix here
[xonotic/xonotic.git] / misc / tools / xonotic-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 ~/.xonotic-map-compiler
9 # (just copy paste this part to the file ~/.xonotic-map-compiler)
10
11         # Path to Xonotic (where the data directory is in)
12         our $XONOTICDIR  = getcwd();
13
14         # Path to your q3map2 program. You find it in your GtkRadiant/install
15         # directory.
16         our $Q3MAP2      = getcwd() . '/netradiant/install/q3map2';
17
18         # General flags for q3map2 (for example -threads 4)
19         our $Q3MAP2FLAGS = '-fs_forbiddenpath xonotic*-data*.pk3* -fs_forbiddenpath xonotic*-nexcompat*.pk3*';
20
21         # Default flags for the -bsp stage
22         our $BSPFLAGS    = '-meta -maxarea -samplesize 8 -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  = '-lightmapsearchpower 3 -deluxe -patchshadows -randomsamples -samples 4 -lightmapsize 512 -fast -fastbounce -dirty -bouncegrid -fill';
29
30         # Default flags for the -minimap stage
31         our $MINIMAPFLAGS = '';
32
33         # Default order of commands
34         our $ORDER = 'vis,light';
35
36 # end of user changable part
37
38 do "$ENV{HOME}/.xonotic-map-compiler";
39
40 sub Usage()
41 {
42         print <<EOF;
43 Usage:
44 $0 mapname [-bsp bspflags...] [-vis visflags...] [-light lightflags...] [-minimap minimapflags]
45 EOF
46         exit 1;
47 }
48
49 my $options =
50 {
51         bsp => [split /\s+/, $BSPFLAGS],
52         vis => [split /\s+/, $VISFLAGS],
53         light => [split /\s+/, $LIGHTFLAGS],
54         minimap => [split /\s+/, $MINIMAPFLAGS],
55         scale => [], # can't have defaults atm
56         order => [split /\s*,\s*/, $ORDER],
57         maps => [],
58         scalefactor => 1,
59         bsp_timeout => 0,
60         vis_timeout => 0,
61         light_timeout => 0,
62         minimap_timeout => 0,
63         scale_timeout => 0
64 };
65
66 my $curmode = 'maps';
67
68 while(@ARGV)
69 {
70         $_ = shift @ARGV;
71         my $enterflags = undef;
72         if($_ eq '-bsp')
73         {
74                 $enterflags = 'bsp';
75         }
76         elsif($_ eq '-vis')
77         {
78                 $enterflags = 'vis';
79         }
80         elsif($_ eq '-light')
81         {
82                 $enterflags = 'light';
83         }
84         elsif($_ eq '-minimap')
85         {
86                 $enterflags = 'minimap';
87         }
88         elsif($_ eq '-map')
89         {
90                 $curmode = 'maps';
91         }
92         elsif($_ eq '-scale')
93         {
94                 $options->{scalefactor} = @ARGV ? shift(@ARGV) : 1;
95                 $enterflags = 'scale';
96         }
97         elsif($_ eq '-novis')
98         {
99                 $options->{vis} = undef;
100         }
101         elsif($_ eq '-nolight')
102         {
103                 $options->{light} = undef;
104         }
105         elsif($_ eq '-nominimap')
106         {
107                 $options->{minimap} = undef;
108         }
109         elsif($_ eq '-bsp_timeout')
110         {
111                 $options->{bsp_timeout} = shift @ARGV;
112         }
113         elsif($_ eq '-vis_timeout')
114         {
115                 $options->{vis_timeout} = shift @ARGV;
116         }
117         elsif($_ eq '-light_timeout')
118         {
119                 $options->{light_timeout} = shift @ARGV;
120         }
121         elsif($_ eq '-minimap_timeout')
122         {
123                 $options->{minimap_timeout} = shift @ARGV;
124         }
125         elsif($_ eq '-scale_timeout')
126         {
127                 $options->{scale_timeout} = shift @ARGV;
128         }
129         elsif($_ eq '-order')
130         {
131                 $options->{order} = [split /\s*,\s*/, shift @ARGV];
132         }
133         elsif($_ eq '-sRGB')
134         {
135                 push @{$options->{bsp}}, "-sRGBtex", "-sRGBcolor";
136                 push @{$options->{light}}, "-sRGBtex", "-sRGBcolor", "-sRGBlight"
137                         if defined $options->{light};
138         }
139         elsif($_ eq '-nosRGB')
140         {
141                 push @{$options->{bsp}}, "-nosRGBtex", "-nosRGBcolor";
142                 push @{$options->{light}}, "-nosRGBtex", "-nosRGBcolor", "-nosRGBlight"
143                         if defined $options->{light};
144         }
145         elsif($_ =~ /^--no(-.*)/)
146         {
147                 if($curmode eq 'maps')
148                 {
149                         $curmode = 'bsp';
150                 }
151                 my $flag = $1;
152                 @{$options->{$curmode}} = grep { (($_ eq $flag) ... /^-/) !~ /^[0-9]+$/ } @{$options->{$curmode}};
153                         # so, e.g. --no-samplesize removes "-samplesize" and a following "3"
154         }
155         elsif($_ =~ /^-(-.*)/)
156         {
157                 if($curmode eq 'maps')
158                 {
159                         $curmode = 'bsp';
160                 }
161                 push @{$options->{$curmode}}, $1;
162         }
163         elsif($_ =~ /^-/ and $curmode eq 'maps')
164         {
165                 $curmode = 'bsp';
166                 push @{$options->{$curmode}}, $_;
167         }
168         else
169         {
170                 push @{$options->{$curmode}}, $_;
171         }
172         if(defined $enterflags)
173         {
174                 $curmode = $enterflags;
175                 if($ARGV[0] eq '+')
176                 {
177                         shift @ARGV;
178                 }
179                 else
180                 {
181                         $options->{$curmode} = [];
182                 }
183         }
184 }
185
186 my $linkdir = File::Temp::tempdir("xonotic-map-compiler.XXXXXX", TMPDIR => 1, CLEANUP => 1);
187
188 sub q3map2(@)
189 {
190         my $mode = $_[0];
191         my $timeout = undef;
192         $timeout = $options->{bsp_timeout} if $mode eq '-bsp';
193         $timeout = $options->{vis_timeout} if $mode eq '-vis';
194         $timeout = $options->{light_timeout} if $mode eq '-light';
195         $timeout = $options->{minimap_timeout} if $mode eq '-minimap';
196         $timeout = $options->{scale_timeout} if $mode eq '-scale';
197         die "Invalid call: not a standard q3map2 stage" if not defined $timeout;
198         my @args = ($Q3MAP2, split(/\s+/, $Q3MAP2FLAGS), '-game', 'xonotic', '-fs_basepath', $XONOTICDIR, '-fs_basepath', $linkdir, '-v', @_);
199         print "\$ @args\n";
200         defined(my $pid = fork())
201                 or die "fork: $!";
202         if($pid) # parent
203         {
204                 local $SIG{ALRM} = sub { warn "SIGALRM caught\n"; kill TERM => $pid; };
205                 alarm $timeout
206                         if $timeout;
207                 if(waitpid($pid, 0) != $pid)
208                 {
209                         die "waitpid: did not return our child process $pid: $!";
210                 }
211                 alarm 0;
212                 return ($? == 0);
213         }
214         else # child
215         {
216                 exec @args
217                         or die "exec: $!";
218         }
219 }
220
221 my ($prescale, $postscale) = ($options->{scalefactor} =~ /^([0-9.]+)(?::([0-9.]+))?$/);
222 $prescale = 1 if not defined $prescale;
223 $postscale = 1 if not defined $postscale;
224
225 my $origcwd = getcwd();
226 for my $m(@{$options->{maps}})
227 {
228         chdir $origcwd
229                 or die "chdir $origcwd: $!";
230         if($m =~ s!(.*)/!!)
231         {
232                 my $predir = $1;
233                 chdir $predir
234                         or die "chdir $predir: $!";
235         }
236         symlink getcwd() . "/..", "$linkdir/data"
237                 or die "symlink $linkdir/data: $!";
238
239         $m =~ s/\.(?:map|bsp)$//;
240
241         if($prescale != 1)
242         {
243                 unshift @{$options->{bsp}}, "-keeplights";
244         }
245
246         local $SIG{INT} = sub
247         {
248                 print "SIGINT caught, cleaning up...\n";
249                 exit 0;
250         };
251
252         unlink <$m/lm_*>; # delete old external lightmaps
253         q3map2 '-bsp', @{$options->{bsp}},   "$m.map"
254                 or die "-bsp: $?";
255         if($prescale != 1)
256         {
257                 q3map2 '-scale', @{$options->{scale}}, $prescale, "$m.bsp"
258                         or die "-scale: $?";
259                 rename "${m}_s.bsp", "$m.bsp"
260                         or die "rename ${m}_s.bsp $m.bsp: $!";
261         }
262         my @o = @{$options->{order}};
263         push @o, qw/light vis/;
264         my %o = ();
265
266         for(@o)
267         {
268                 next if $o{$_}++;
269                 if($_ eq 'light')
270                 {
271                         if(defined $options->{light})
272                         {
273                                 q3map2 '-light',        @{$options->{light}}, "$m.map"
274                                         or die "-light: $?";
275                         }
276                 }
277                 if($_ eq 'vis')
278                 {
279                         if(defined $options->{vis})
280                         {
281                                 q3map2 '-vis',          @{$options->{vis}},   "$m.map"
282                                         or die "-vis: $?";
283                         }
284                 }
285         }
286
287         if($postscale != 1)
288         {
289                 q3map2 '-scale', @{$options->{scale}}, $postscale, "$m.bsp"
290                         or die "-scale: $?";
291                 rename "${m}_s.bsp", "$m.bsp"
292                         or die "rename ${m}_s.bsp $m.bsp: $!";
293         }
294
295         if(defined $options->{minimap})
296         {
297                 q3map2 '-minimap',      @{$options->{minimap}}, "$m.map"
298                         or die "-minimap: $?";
299         }
300
301         unlink "$m.srf";
302         unlink "$m.prt";
303 }