]> icculus.org git repositories - divverent/nexuiz.git/blob - misc/entmerge.pl
more entmerge... still not working well
[divverent/nexuiz.git] / misc / entmerge.pl
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5
6 # ent file managing tool
7 # usage:
8 #
9 #   map -> ent:
10 #     perl entmerge.pl $scalefactor             < mapname.map > mapname.ent
11 #
12 #   ent -> map:
13 #     perl entmerge.pl $scalefactor mapname.ent < mapname.map > mapname-merged.map
14 #
15 #   bsp -> ent:
16 #     perl bsptool.pl mapname.bsp -xentities                  > mapname.ent
17 #                                                          
18 #   ent -> bsp:                                            
19 #     perl bsptool.pl mapname.bsp -rentities                  < mapname.ent
20
21 sub BrushOrigin($)
22 {
23         warn "Origin brushes not supported yet";
24         return undef;
25 }
26
27 sub ParseEntity($)
28 {
29         my ($fh) = @_;
30
31         my %ent = ( );
32         my @brushes = ( );
33
34         while(<$fh>)
35         {
36                 chomp; s/\r//g; s/\0//g; s/\/\/.*$//; s/^\s+//; s/\s+$//; next if /^$/;
37
38                 if(/^\{$/)
39                 {
40                         # entity starts
41                         while(<$fh>)
42                         {
43                                 chomp; s/\r//g; s/\0//g; s/\/\/.*$//; s/^\s+//; s/\s+$//; next if /^$/;
44
45                                 if(/^"(.*?)" "(.*)"$/)
46                                 {
47                                         # key-value pair
48                                         $ent{$1} = $2;
49                                 }
50                                 elsif(/^\{$/)
51                                 {
52                                         my $brush = [];
53                                         push @brushes, $brush;
54
55                                         while(<$fh>)
56                                         {
57                                                 chomp; s/\r//g; s/\0//g; s/\/\/.*$//; s/^\s+//; s/\s+$//; next if /^$/;
58
59                                                 if(/^\{$/)
60                                                 {
61                                                         # patch?
62                                                         push @$brush, $_;
63
64                                                         while(<$fh>)
65                                                         {
66                                                                 chomp; s/\r//g; s/\0//g; s/\/\/.*$//; s/^\s+//; s/\s+$//; next if /^$/;
67
68                                                                 if(/^\}$/)
69                                                                 {
70                                                                         push @$brush, $_;
71
72                                                                         last;
73                                                                 }
74                                                                 else
75                                                                 {
76                                                                         push @$brush, $_;
77                                                                 }
78                                                         }
79                                                 }
80                                                 elsif(/^\}$/)
81                                                 {
82                                                         # end of brush
83                                                         last;
84                                                 }
85                                                 else
86                                                 {
87                                                         push @$brush, $_;
88                                                 }
89                                         }
90                                 }
91                                 elsif(/^\}$/)
92                                 {
93                                         return \%ent, \@brushes;
94                                 }
95                         }
96                 }
97                 else
98                 {
99                         die "Unexpected line in top level: >>$_<<";
100                 }
101         }
102
103         return undef;
104 }
105
106 sub UnparseEntity($$)
107 {
108         my ($ent, $brushes) = @_;
109         my %ent = %$ent;
110
111         my $s = "{\n";
112
113         for(sort keys %ent)
114         {
115                 $s .= "\"$_\" \"$ent{$_}\"\n";
116         }
117
118         if(defined $brushes)
119         {
120                 for(@$brushes)
121                 {
122                         $s .= "{\n";
123                         $s .= "$_\n" for @$_;
124                         $s .= "}\n";
125                 }
126         }
127
128         $s .= "}\n";
129         return $s;
130 }
131
132 my ($scale, $in_ent) = @ARGV;
133
134 $scale = 1
135         if not defined $scale;
136
137 my @submodels = ();
138 my @entities = ();
139 my @entities_skipped = ();
140
141 # THIS part is always a .map file
142 my $first = 1;
143 my $keeplights;
144 for(;;)
145 {
146         my ($ent, $brushes) = ParseEntity \*STDIN;
147
148         defined $ent
149                 or last;
150         
151         if($first && $ent->{classname} eq 'worldspawn')
152         {
153                 $keeplights = $ent->{_keeplights};
154                 delete $ent->{_keeplights};
155                 @submodels = ($brushes);
156         }
157         else
158         {
159                 if($first)
160                 {
161                         push @entities, { classname => "worldspawn" };
162                         @submodels = ([]);
163                 }
164
165                 if($ent->{classname} eq 'worldspawn')
166                 {
167                         $ent->{classname} = "worldspawn_renamed";
168                 }
169
170                 if(grep { $_ eq $ent->{classname} } qw/group_info func_group misc_model _decal _skybox/)
171                 {
172                         push @entities_skipped, [$ent, $brushes];
173                         next;
174                 }
175
176                 if(!$keeplights && $ent->{classname} =~ /^light/)
177                 {
178                         push @entities_skipped, [$ent, $brushes];
179                         next;
180                 }
181
182                 if(@$brushes)
183                 {
184                         my $i = @submodels;
185                         push @submodels, $brushes;
186                         $ent->{model} = sprintf "*%d", $i;
187                 }
188         }
189
190         push @entities, $ent;
191
192         $first = 0;
193 }
194
195 if($first)
196 {
197         push @entities, { classname => "worldspawn" };
198         @submodels = ([]);
199 }
200
201 if(defined $in_ent)
202 {
203         # translate map using ent to map
204         open my $fh, "<", $in_ent
205                 or die "$in_ent: $!";
206
207         # THIS part is always an .ent file now
208         my @entities_entfile = ();
209         $first = 1;
210         for(;;)
211         {
212                 my ($ent, $brushes) = ParseEntity $fh;
213
214                 defined $ent
215                         or last;
216                 
217                 if($first && $ent->{classname} eq 'worldspawn')
218                 {
219                 }
220                 else
221                 {
222                         if($first)
223                         {
224                                 push @entities_entfile, { classname => "worldspawn" };
225                         }
226
227                         if($ent->{classname} eq 'worldspawn')
228                         {
229                                 $ent->{classname} = "worldspawn_renamed";
230                         }
231                 }
232
233                 push @entities_entfile, $ent;
234                 $first = 0;
235         }
236         close $fh;
237
238         if($first)
239         {
240                 push @entities_entfile, { classname => "worldspawn" };
241         }
242
243         $first = 1;
244         for(@entities_entfile)
245         {
246                 my %e = %$_;
247                 my $submodel = undef;
248
249                 $e{gridsize} = "64 64 128" if not exists $e{gridsize};
250                 $e{lip} /= $scale if exists $e{lip};
251                 $e{origin} = join ' ', map { $_ / $scale } split /\s+/, $e{origin} if exists $e{origin};
252                 $e{gridsize} = join ' ', map { $_ / $scale } split /\s+/, $e{gridsize} if exists $e{gridsize} and $first;
253
254                 if($first)
255                 {
256                         $submodel = $submodels[0];
257                         $e{_keeplights} = 1
258                                 if $keeplights;
259                 }
260                 elsif(defined $e{model} and $e{model} =~ /^\*(\d+)$/)
261                 {
262                         $submodel = $submodels[$1];
263                         delete $e{model};
264                 }
265                 print UnparseEntity \%e, $submodel;
266                 $first = 0;
267         }
268         for(@entities_skipped)
269         {
270                 print UnparseEntity $_->[0], $_->[1];
271                 $first = 0;
272         }
273 }
274 else
275 {
276         # translate map to ent
277         $first = 1;
278         for(@entities)
279         {
280                 my %e = %$_;
281
282                 if(defined $e{model} and $e{model} =~ /^\*(\d+)$/)
283                 {
284                         my $org = BrushOrigin $submodels{$e{origin}};
285                         $e{origin} = $org
286                                 if defined $org;
287                 }
288
289                 $e{gridsize} = "64 64 128" if not exists $e{gridsize};
290                 $e{lip} *= $scale if exists $e{lip};
291                 $e{origin} = join ' ', map { $_ * $scale } split /\s+/, $e{origin} if exists $e{origin};
292                 $e{gridsize} = join ' ', map { $_ * $scale } split /\s+/, $e{gridsize} if exists $e{gridsize} and $first;
293
294                 print UnparseEntity \%e, undef;
295                 $first = 0;
296         }
297 }