xonotic/misc/tools/xonotic-map-compiler

379 lines
7.9 KiB
Plaintext
Raw Normal View History

2010-03-18 13:22:15 +00:00
#!/usr/bin/perl
use strict;
use warnings;
use POSIX;
use File::Temp;
# change these to match your system, or define them in ~/.xonotic-map-compiler
# (just copy paste this part to the file ~/.xonotic-map-compiler)
2010-03-18 13:22:15 +00:00
# Path to Xonotic (where the data directory is in)
our $XONOTICDIR = '/home/rpolzer/Games/Xonotic';
2010-03-18 13:22:15 +00:00
# Path to your q3map2 program. You find it in your GtkRadiant/install
# directory.
our $Q3MAP2 = '/home/rpolzer/Games/Xonotic/netradiant/install/q3map2.x86';
2010-03-18 13:22:15 +00:00
# General flags for q3map2 (for example -threads 4)
2011-07-01 09:43:32 +00:00
our $Q3MAP2FLAGS = '-fs_forbiddenpath xonotic*-data*.pk3* -fs_forbiddenpath xonotic*-nexcompat*.pk3*';
2010-03-18 13:22:15 +00:00
# Default flags for the -bsp stage
our $BSPFLAGS = '-meta -maxarea -samplesize 8 -mv 1000000 -mi 6000000';
2010-03-18 13:22:15 +00:00
# Default flags for the -vis stage
our $VISFLAGS = '';
# Default flags for the -light stage
2010-10-31 11:53:46 +00:00
our $LIGHTFLAGS = '-lightmapsearchpower 3 -deluxe -patchshadows -randomsamples -samples 4 -lightmapsize 512 -fast -fastbounce -dirty -bouncegrid -fill';
2010-03-18 13:22:15 +00:00
# Default flags for the -minimap stage
our $MINIMAPFLAGS = '';
# Default order of commands
our $ORDER = 'vis,light';
2010-03-18 13:22:15 +00:00
# end of user changable part
do "$ENV{HOME}/.xonotic-map-compiler";
2010-03-18 13:22:15 +00:00
sub Usage()
{
print <<EOF;
Usage:
2010-07-04 17:14:39 +00:00
$0 mapname [-bsp bspflags...] [-vis visflags...] [-light lightflags...] [-minimap minimapflags]
2010-03-18 13:22:15 +00:00
EOF
exit 1;
}
my $options =
{
bsp => [split /\s+/, $BSPFLAGS],
vis => [split /\s+/, $VISFLAGS],
light => [split /\s+/, $LIGHTFLAGS],
minimap => [split /\s+/, $MINIMAPFLAGS],
2010-07-04 17:14:39 +00:00
scale => [], # can't have defaults atm
2010-03-18 13:22:15 +00:00
order => [split /\s*,\s*/, $ORDER],
maps => [],
2010-11-06 15:37:35 +00:00
scalefactor => 1,
bsp_timeout => 0,
vis_timeout => 0,
light_timeout => 0,
minimap_timeout => 0,
scale_timeout => 0
2010-03-18 13:22:15 +00:00
};
my $curmode = 'maps';
while(@ARGV)
{
$_ = shift @ARGV;
my $enterflags = undef;
if($_ eq '-bsp')
{
$enterflags = 'bsp';
}
elsif($_ eq '-vis')
{
$enterflags = 'vis';
}
elsif($_ eq '-light')
{
$enterflags = 'light';
}
elsif($_ eq '-minimap')
{
$enterflags = 'minimap';
}
elsif($_ eq '-map')
{
$curmode = 'maps';
}
elsif($_ eq '-scale')
{
2010-11-06 15:37:35 +00:00
$options->{scalefactor} = @ARGV ? shift(@ARGV) : 1;
$enterflags = 'scale';
2010-03-18 13:22:15 +00:00
}
elsif($_ eq '-novis')
{
$options->{vis} = undef;
}
elsif($_ eq '-nolight')
{
$options->{light} = undef;
}
elsif($_ eq '-nominimap')
{
$options->{minimap} = undef;
}
2010-05-06 14:58:03 +00:00
elsif($_ eq '-noshaderlist')
{
$options->{noshaderlist} = 1;
}
elsif($_ eq '-bsp_timeout')
{
$options->{bsp_timeout} = shift @ARGV;
}
elsif($_ eq '-vis_timeout')
{
$options->{vis_timeout} = shift @ARGV;
}
elsif($_ eq '-light_timeout')
{
$options->{light_timeout} = shift @ARGV;
}
elsif($_ eq '-minimap_timeout')
{
$options->{minimap_timeout} = shift @ARGV;
}
elsif($_ eq '-scale_timeout')
{
2010-11-06 15:37:35 +00:00
$options->{scale_timeout} = shift @ARGV;
}
2010-03-18 13:22:15 +00:00
elsif($_ eq '-order')
{
$options->{order} = [split /\s*,\s*/, shift @ARGV];
}
elsif($_ eq '-sRGB')
{
push @{$options->{bsp}}, "-sRGBtex", "-sRGBcolor";
push @{$options->{light}}, "-sRGBtex", "-sRGBcolor", "-sRGBlight";
}
elsif($_ eq '-nosRGB')
{
push @{$options->{bsp}}, "-nosRGBtex", "-nosRGBcolor";
push @{$options->{light}}, "-nosRGBtex", "-nosRGBcolor", "-nosRGBlight";
}
elsif($_ =~ /^--no(-.*)/)
{
if($curmode eq 'maps')
{
$curmode = 'bsp';
}
my $flag = $1;
@{$options->{$curmode}} = grep { (($_ eq $flag) ... /^-/) !~ /^[0-9]+$/ } @{$options->{$curmode}};
# so, e.g. --no-samplesize removes "-samplesize" and a following "3"
}
2010-03-18 13:22:15 +00:00
elsif($_ =~ /^-(-.*)/)
{
if($curmode eq 'maps')
{
$curmode = 'bsp';
}
push @{$options->{$curmode}}, $1;
}
elsif($_ =~ /^-/ and $curmode eq 'maps')
{
$curmode = 'bsp';
push @{$options->{$curmode}}, $_;
}
else
{
push @{$options->{$curmode}}, $_;
}
if(defined $enterflags)
{
$curmode = $enterflags;
if($ARGV[0] eq '+')
{
shift @ARGV;
}
else
{
$options->{$curmode} = [];
}
}
}
my $linkdir = File::Temp::tempdir("xonotic-map-compiler.XXXXXX", TMPDIR => 1, CLEANUP => 1);
2010-03-18 13:22:15 +00:00
sub q3map2(@)
{
my $mode = $_[0];
my $timeout = undef;
$timeout = $options->{bsp_timeout} if $mode eq '-bsp';
$timeout = $options->{vis_timeout} if $mode eq '-vis';
$timeout = $options->{light_timeout} if $mode eq '-light';
$timeout = $options->{minimap_timeout} if $mode eq '-minimap';
$timeout = $options->{scale_timeout} if $mode eq '-scale';
die "Invalid call: not a standard q3map2 stage" if not defined $timeout;
my @args = ($Q3MAP2, split(/\s+/, $Q3MAP2FLAGS), '-game', 'xonotic', '-fs_basepath', $XONOTICDIR, '-fs_basepath', $linkdir, '-v', @_);
2010-03-18 13:22:15 +00:00
print "\$ @args\n";
defined(my $pid = fork())
or die "fork: $!";
if($pid) # parent
{
2010-07-21 13:03:35 +00:00
local $SIG{ALRM} = sub { warn "SIGALRM caught\n"; kill TERM => $pid; };
2010-07-19 06:34:34 +00:00
alarm $timeout
if $timeout;
2010-07-19 07:16:54 +00:00
if(waitpid($pid, 0) != $pid)
{
die "waitpid: did not return our child process $pid: $!";
}
2010-07-19 07:16:54 +00:00
alarm 0;
2010-07-19 12:39:21 +00:00
return ($? == 0);
}
else # child
{
exec @args
or die "exec: $!";
}
2010-03-18 13:22:15 +00:00
}
(my $mapdir = getcwd()) =~ s!/[^/]*(?:$)!!;
$mapdir = "/" if $mapdir eq "";
symlink "$mapdir", "$linkdir/data";
2010-11-06 15:37:35 +00:00
my ($prescale, $postscale) = ($options->{scalefactor} =~ /^([0-9.]+)(?::([0-9.]+))?$/);
$prescale = 1 if not defined $prescale;
2010-03-18 13:22:15 +00:00
$postscale = 1 if not defined $postscale;
for my $m(@{$options->{maps}})
{
$m =~ s/\.(?:map|bsp)$//;
2010-03-18 13:22:15 +00:00
if($prescale != 1)
{
unshift @{$options->{bsp}}, "-keeplights";
2010-03-18 13:22:15 +00:00
}
my %shaders = map { m!/([^/.]*)\.shader(?:$)! ? ($1 => 1) : () } glob "../scripts/*.shader";
2010-05-06 14:58:03 +00:00
my $restore_shaderlist = sub { };
if(!$options->{noshaderlist})
2010-03-18 13:22:15 +00:00
{
2010-05-06 14:58:03 +00:00
my $previous_shaderlist = undef;
my $shaderlist = "";
2010-05-27 14:04:53 +00:00
if(open my $fh, "<", "$XONOTICDIR/data/scripts/shaderlist.txt")
2010-03-18 13:22:15 +00:00
{
2010-05-06 14:58:03 +00:00
while(<$fh>)
{
$shaderlist .= $_;
}
2010-03-18 13:22:15 +00:00
2010-05-06 14:58:03 +00:00
# we may have to restore the file on exit
$previous_shaderlist = $shaderlist
if "$XONOTICDIR/data" eq $mapdir;
}
else
{
# possibly extract the shader list from a pk3?
local $ENV{N} = $XONOTICDIR;
$shaderlist = `cd "\$N" && for X in "\$N"/data/data*.pk3; do Y=\$X; done; unzip -p "\$Y" scripts/shaderlist.txt`;
}
2010-03-18 13:22:15 +00:00
2010-05-06 14:58:03 +00:00
my $shaderlist_new = "";
for(split /\r?\n|\r/, $shaderlist)
2010-03-18 13:22:15 +00:00
{
2010-05-06 14:58:03 +00:00
delete $shaders{$_};
2010-03-18 13:22:15 +00:00
$shaderlist_new .= "$_\n";
}
2010-05-06 14:58:03 +00:00
if(%shaders)
2010-03-18 13:22:15 +00:00
{
2010-05-06 14:58:03 +00:00
for(sort keys %shaders)
2010-03-18 13:22:15 +00:00
{
2010-05-06 14:58:03 +00:00
$shaderlist_new .= "$_\n";
2010-03-18 13:22:15 +00:00
}
2010-05-06 14:58:03 +00:00
}
else
{
$shaderlist_new = undef;
}
$restore_shaderlist = sub
{
if(defined $shaderlist_new)
2010-03-18 13:22:15 +00:00
{
2010-05-06 14:58:03 +00:00
if(defined $previous_shaderlist)
{
open my $fh, ">", "$mapdir/scripts/shaderlist.txt";
print $fh $previous_shaderlist;
close $fh;
}
else
{
unlink "$mapdir/scripts/shaderlist.txt";
}
2010-03-18 13:22:15 +00:00
}
2010-05-06 14:58:03 +00:00
};
2010-05-06 15:00:41 +00:00
if(defined $shaderlist_new)
{
mkdir "$mapdir/scripts";
open my $fh, ">", "$mapdir/scripts/shaderlist.txt";
print $fh $shaderlist_new;
close $fh;
}
2010-05-06 14:58:03 +00:00
}
2010-03-18 13:22:15 +00:00
local $SIG{INT} = sub
{
print "SIGINT caught, cleaning up...\n";
$restore_shaderlist->();
exit 0;
};
eval
{
unlink <$m/lm_*>; # delete old external lightmaps
q3map2 '-bsp', @{$options->{bsp}}, "$m.map"
or die "-bsp: $?";
if($prescale != 1)
{
2010-11-06 15:37:35 +00:00
q3map2 '-scale', @{$options->{scale}}, $prescale, "$m.bsp"
2010-03-18 13:22:15 +00:00
or die "-scale: $?";
rename "${m}_s.bsp", "$m.bsp"
or die "rename ${m}_s.bsp $m.bsp: $!";
}
my @o = @{$options->{order}};
push @o, qw/light vis/;
2010-03-18 13:22:15 +00:00
my %o = ();
for(@o)
{
next if $o{$_}++;
if($_ eq 'light')
{
if(defined $options->{light})
{
q3map2 '-light', @{$options->{light}}, "$m.map"
or die "-light: $?";
}
}
if($_ eq 'vis')
{
if(defined $options->{vis})
{
q3map2 '-vis', @{$options->{vis}}, "$m.map"
or die "-vis: $?";
}
}
}
if($postscale != 1)
{
2010-11-06 15:37:35 +00:00
q3map2 '-scale', @{$options->{scale}}, $postscale, "$m.bsp"
2010-03-18 13:22:15 +00:00
or die "-scale: $?";
rename "${m}_s.bsp", "$m.bsp"
or die "rename ${m}_s.bsp $m.bsp: $!";
}
if(defined $options->{minimap})
{
q3map2 '-minimap', @{$options->{minimap}}, "$m.map"
or die "-minimap: $?";
}
2010-03-18 13:22:15 +00:00
unlink "$m.srf";
unlink "$m.prt";
$restore_shaderlist->();
1;
}
or do
{
$restore_shaderlist->();
die $@;
};
}