put NetRadiant's NexuizPack here
[divverent/nexuiz.git] / misc / tools / nexuiz-map-compiler
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5 use POSIX;
6
7 # change these to match your system, or define them in ~/.nexuiz-map-compiler
8 # (just copy paste this part to the file ~/.nexuiz-map-compiler)
9
10         # Path to Nexuiz (where the data directory is in)
11         our $NEXUIZDIR   = '/home/polzer/Nexvn/nexuiz';
12
13         # Path to your q3map2 program. You find it in your GtkRadiant/install
14         # directory.
15         our $Q3MAP2      = '/home/users4/ommz/polzer/bin/q3map2.x86';
16
17         # General flags for q3map2 (for example -threads 4)
18         our $Q3MAP2FLAGS = '';
19
20         # Default flags for the -bsp stage
21         our $BSPFLAGS    = '-samplesize 8 -minsamplesize 4 -mv 1000000 -mi 6000000';
22
23         # Default flags for the -vis stage
24         our $VISFLAGS    = '';
25
26         # Default flags for the -light stage
27         our $LIGHTFLAGS  = '-deluxe -patchshadows -samples 3 -lightmapsize 512 -bounce 8 -fastbounce -bouncegrid';
28
29 # end of user changable part
30
31 do "$ENV{HOME}/.nexuiz-map-compiler";
32
33 sub Usage()
34 {
35         print <<EOF;
36 Usage:
37 $0 mapname [-bsp bspflags...] [-vis visflags...] [-light lightflags...]
38 EOF
39         exit 1;
40 }
41
42 my $options =
43 {
44         bsp => [split /\s+/, $BSPFLAGS],
45         vis => [split /\s+/, $VISFLAGS],
46         light => [split /\s+/, $LIGHTFLAGS],
47         maps => [],
48         scale => 1
49 };
50
51 my $curmode = 'maps';
52
53 while(@ARGV)
54 {
55         $_ = shift @ARGV;
56         my $enterflags = undef;
57         if($_ eq '-bsp' or $_ eq '-meta')
58         {
59                 $enterflags = 'bsp';
60         }
61         elsif($_ eq '-vis')
62         {
63                 $enterflags = 'vis';
64         }
65         elsif($_ eq '-light')
66         {
67                 $enterflags = 'light';
68         }
69         elsif($_ eq '-map')
70         {
71                 $curmode = 'maps';
72         }
73         elsif($_ eq '-scale')
74         {
75                 $options->{scale} = (shift @ARGV) || 1;
76         }
77         elsif($_ eq '-novis')
78         {
79                 $options->{vis} = undef;
80         }
81         elsif($_ eq '-nolight')
82         {
83                 $options->{light} = undef;
84         }
85         elsif($_ =~ /^-(-.*)/)
86         {
87                 if($curmode eq 'maps')
88                 {
89                         $curmode = 'bsp';
90                 }
91                 push @{$options->{$curmode}}, $1;
92         }
93         elsif($_ =~ /^-/ and $curmode eq 'maps')
94         {
95                 $curmode = 'bsp';
96                 push @{$options->{$curmode}}, $_;
97         }
98         else
99         {
100                 push @{$options->{$curmode}}, $_;
101         }
102         if(defined $enterflags)
103         {
104                 $curmode = $enterflags;
105                 if($ARGV[0] eq '+')
106                 {
107                         shift @ARGV;
108                 }
109                 else
110                 {
111                         $options->{$curmode} = [];
112                 }
113         }
114 }
115
116 my $game = 'compile.' . int rand 99999999; # mktemp on win32?
117
118 sub q3map2(@)
119 {
120         my @args = ($Q3MAP2, split(/\s+/, $Q3MAP2FLAGS), '-game', 'nexuiz', '-fs_basepath', $NEXUIZDIR, '-fs_game', $game, '-v', @_);
121         print "\$ @args\n";
122         return !system @args;
123 }
124
125 (my $mapdir = getcwd()) =~ s!/[^/]*(?:$)!!;
126 $mapdir = "/" if $mapdir eq "";
127
128 unlink "$NEXUIZDIR/$game";
129 mkdir "$NEXUIZDIR";
130 eval
131 {
132         symlink "$mapdir", "$NEXUIZDIR/$game"
133                 or die "THROW: Setting up directory structure, $mapdir -> $NEXUIZDIR/$game: $!";
134         1;
135 }
136 or do
137 {
138         die $1
139                 if $@ =~ /^THROW: (.*)/s;
140         # if we get here, symlinks do not work, as symlink() itself raised the exception
141         # this should only happen on Win32
142         if($^O ne "MSWin32")
143         {
144                 die "Symlinks not supported ($@) but invalid OS signature, this must be MSWin32, but $^O got reported";
145         }
146
147         # TODO support Windows here somehow
148         # maybe by copying all files and copying back the finished compile? (ugh)
149         die "Windows is not supported yet.";
150 };
151
152 my ($prescale, $postscale) = ($options->{scale} =~ /^([0-9.]+)(?::([0-9.]+))?$/);
153 $postscale = 1 if not defined $postscale;
154
155 for my $m(@{$options->{maps}})
156 {
157         if($prescale != 1 or $postscale != 1)
158         {
159                 open my $checkfh, "<", "$m.map"
160                         or die "open $m.map: $!";
161                 my $keeplights = 0;
162                 while(<$checkfh>)
163                 {
164                         /^\s*"_keeplights"\s+"1"\s*$/
165                                 or next;
166                         $keeplights = 1;
167                 }
168                 close $checkfh;
169                 die "$m does not define _keeplights to 1"
170                         unless $keeplights;
171         }
172
173         my %shaders = map { m!/([^/.]*)\.shader(?:$)! ? ($1 => 1) : () } glob "../scripts/*.shader";
174         open my $shaderlist, "+<", "$NEXUIZDIR/data/scripts/shaderlist.txt"
175                 or die "open $NEXUIZDIR/data/scripts/shaderlist.txt: $!";
176         my $previous_shaderlist = "";
177         while(<$shaderlist>)
178         {
179                 $previous_shaderlist .= $_;
180                 y/\r\n//d;
181                 delete $shaders{$_};
182         }
183         my $restore_shaderlist = sub
184         {
185                 open $shaderlist, ">", "$NEXUIZDIR/data/scripts/shaderlist.txt";
186                 print $shaderlist $previous_shaderlist;
187                 close $shaderlist;
188         };
189         local $SIG{INT} = sub
190         {
191                 print "SIGINT caught, cleaning up...\n";
192                 $restore_shaderlist->();
193                 exit 0;
194         };
195         eval
196         {
197                 for(keys %shaders)
198                 {
199                         print $shaderlist "$_\n";
200                 }
201                 close $shaderlist;
202
203                 unlink <$m/lm_*>; # delete old external lightmaps
204                 q3map2 '-bsp', '-meta', @{$options->{bsp}},   "$m.map"
205                         or die "-bsp: $?";
206                 if($prescale != 1)
207                 {
208                         q3map2 '-scale', $prescale, "$m.bsp"
209                                 or die "-scale: $?";
210                         rename "${m}_s.bsp", "$m.bsp"
211                                 or die "rename ${m}_s.bsp $m.bsp: $!";
212                 }
213                 if(defined $options->{vis})
214                 {
215                         q3map2 '-vis',          @{$options->{vis}},   "$m.map"
216                                 or die "-vis: $?";
217                 }
218                 if(defined $options->{light})
219                 {
220                         q3map2 '-light',        @{$options->{light}}, "$m.map"
221                                 or die "-light: $?";
222                 }
223                 if($postscale != 1)
224                 {
225                         q3map2 '-scale', $postscale, "$m.bsp"
226                                 or die "-scale: $?";
227                         rename "${m}_s.bsp", "$m.bsp"
228                                 or die "rename ${m}_s.bsp $m.bsp: $!";
229                 }
230
231                 unlink "$m.srf";
232
233                 $restore_shaderlist->();
234                 1;
235         }
236         or do
237         {
238                 $restore_shaderlist->();
239                 die $@;
240         };
241 }