1#!perl -w 2# 3#v 0.3 Last Edited: 12 June 2011 4########################################################### 5package level; 6use strict; 7use stkutils::chunked_file; 8use stkutils::ini_file; 9#use stkutils::lzhuf; 10use Cwd; 11sub new { 12 my $class = shift; 13 my $self = {}; 14 $self->{fsl_header} = {}; 15 $self->{fsl_shaders} = {}; 16 $self->{fsl_visuals} = {}; 17 $self->{fsl_portals} = {}; 18 $self->{fsl_light_dynamic} = {}; 19 $self->{fsl_glows} = {}; 20 $self->{fsl_sectors} = {}; 21 $self->{fsl_vertex_buffer} = {}; 22 $self->{fsl_index_buffer} = {}; 23 $self->{fsl_swis} = {}; 24 $self->{compressed} = {}; 25 bless($self, $class); 26 return $self; 27} 28sub read { 29 my $self = shift; 30 my ($fn) = @_; 31 32 my $fh = stkutils::chunked_file->new($fn, 'r') or die "$fn: $!\n"; 33 while (1) { 34 my ($index, $size) = $fh->r_chunk_open(); 35 defined $index or last; 36 last unless $index != 0; 37 my $data = $fh->r_chunk_data(); 38# if ($index & 0x80000000) { 39# print "chunk compressed!\n"; 40# my $dec_data = $self->decompress($data, $size); 41# $index -= 0x80000000; 42# print "$index\n"; 43# $data = $dec_data; 44# } 45 SWITCH: { 46 $index == 0x1 && do {$self->fsl_header::read($data); last SWITCH;}; 47 (chunks::get_name($index, $self->{fsl_header}->{xrlc_version}) eq 'FSL_TEXTURES') && do {$self->fsl_textures::read($data); last SWITCH;}; 48 (chunks::get_name($index, $self->{fsl_header}->{xrlc_version}) eq 'FSL_SHADERS') && do {$self->fsl_shaders::read($data); last SWITCH;}; 49 (chunks::get_name($index, $self->{fsl_header}->{xrlc_version}) eq 'FSL_CFORM') && do {$self->fsl_cform::read($data); last SWITCH; }; 50 (chunks::get_name($index, $self->{fsl_header}->{xrlc_version}) eq 'FSL_LIGHT_KEY_FRAMES') && do {$self->fsl_light_key_frames::read($data); last SWITCH;}; 51 (chunks::get_name($index, $self->{fsl_header}->{xrlc_version}) eq 'FSL_SHADER_CONSTANT') && do {$self->fsl_shader_constant::read($data); last SWITCH;}; 52 (chunks::get_name($index, $self->{fsl_header}->{xrlc_version}) eq 'FSL_VISUALS') && do {$self->fsl_visuals::read($data); last SWITCH;}; 53 (chunks::get_name($index, $self->{fsl_header}->{xrlc_version}) eq 'FSL_PORTALS') && do {$self->fsl_portals::read($data); last SWITCH;}; 54 (chunks::get_name($index, $self->{fsl_header}->{xrlc_version}) eq 'FSL_LIGHT_DYNAMIC') && do {$self->fsl_light_dynamic::read($data); last SWITCH;}; 55 (chunks::get_name($index, $self->{fsl_header}->{xrlc_version}) eq 'FSL_GLOWS') && do {$self->fsl_glows::read($data); last SWITCH; }; 56 (chunks::get_name($index, $self->{fsl_header}->{xrlc_version}) eq 'FSL_SECTORS') && do {$self->fsl_sectors::read($data); last SWITCH;}; 57 (chunks::get_name($index, $self->{fsl_header}->{xrlc_version}) eq 'FSL_VB') && do {$self->fsl_vertex_buffer::read($data); last SWITCH;}; 58 (chunks::get_name($index, $self->{fsl_header}->{xrlc_version}) eq 'FSL_VB_OLD') && do {$self->fsl_vertex_buffer::read($data); last SWITCH;}; 59 (chunks::get_name($index, $self->{fsl_header}->{xrlc_version}) eq 'FSL_IB') && do {$self->fsl_index_buffer::read($data); last SWITCH;}; 60 (chunks::get_name($index, $self->{fsl_header}->{xrlc_version}) eq 'FSL_SWIS') && do {$self->fsl_swis::read($data); last SWITCH;}; 61 ($index &0x80000000) && do {$index -= 0x80000000; $self->compressed::read($index, $data); last SWITCH; }; 62 printf "unexpected chunk %04x size %d\n", $index, $size; 63 die; 64 } 65 $fh->r_chunk_close(); 66 } 67} 68sub decompress { 69 my $self = shift; 70 my ($data, $size) = @_; 71 my $huff = stkutils::lzhuf->new($data); 72 $huff->decode($size); 73 return $huff->{dec_data}; 74} 75sub write { 76 my $self = shift; 77 my ($fn) = @_; 78 79 my $fh = stkutils::chunked_file->new($fn, 'w') or die "$fn: $!\n"; 80 $self->fsl_header::write($fh); 81 if ($self->{fsl_header}->{xrlc_version} == 10 || $self->{fsl_header}->{xrlc_version} == 11) { 82 if (defined $self->{fsl_portals}->{raw_data}) { 83 $self->fsl_portals::write($fh); 84 } elsif (defined $self->{compressed}->{chunks::get_index('FSL_PORTALS', $self->{fsl_header}->{xrlc_version})}) { 85 $self->compressed::write(chunks::get_index('FSL_PORTALS', $self->{fsl_header}->{xrlc_version}), $fh); 86 } 87 if (defined $self->{fsl_cform}->{raw_data}) { 88 $self->fsl_cform::write($fh); 89 } elsif (defined $self->{compressed}->{chunks::get_index('FSL_CFORM', $self->{fsl_header}->{xrlc_version})}) { 90 $self->compressed::write(chunks::get_index('FSL_CFORM', $self->{fsl_header}->{xrlc_version}), $fh); 91 } 92 } else { 93 if (defined $self->{fsl_cform}->{raw_data}) { 94 $self->fsl_cform::write($fh); 95 } elsif (defined $self->{compressed}->{chunks::get_index('FSL_CFORM', $self->{fsl_header}->{xrlc_version})}) { 96 $self->compressed::write(chunks::get_index('FSL_CFORM', $self->{fsl_header}->{xrlc_version}), $fh); 97 } 98 if (defined $self->{fsl_portals}->{raw_data}) { 99 $self->fsl_portals::write($fh); 100 } elsif (chunks::get_index('FSL_PORTALS', $self->{fsl_header}->{xrlc_version}) && defined $self->{compressed}->{chunks::get_index('FSL_PORTALS', $self->{fsl_header}->{xrlc_version})}) { 101 $self->compressed::write(chunks::get_index('FSL_PORTALS', $self->{fsl_header}->{xrlc_version}), $fh); 102 } 103 } 104 if (defined $self->{fsl_shader_constant}->{raw_data}) { 105 $self->fsl_shader_constant::write($fh); 106 } elsif (chunks::get_index('FSL_SHADER_CONSTANT', $self->{fsl_header}->{xrlc_version}) && defined $self->{compressed}->{chunks::get_index('FSL_SHADER_CONSTANT', $self->{fsl_header}->{xrlc_version})}) { 107 $self->compressed::write(chunks::get_index('FSL_SHADER_CONSTANT', $self->{fsl_header}->{xrlc_version}), $fh); 108 } 109 $self->fsl_light_dynamic::write($fh); 110 if ($self->{fsl_header}->{xrlc_version} < 8) { 111 if (defined $self->{fsl_light_key_frames}->{raw_data}) { 112 $self->fsl_light_key_frames::write($fh); 113 } elsif (defined $self->{compressed}->{chunks::get_index('FSL_LIGHT_KEY_FRAMES', $self->{fsl_header}->{xrlc_version})}) { 114 $self->compressed::write(chunks::get_index('FSL_LIGHT_KEY_FRAMES', $self->{fsl_header}->{xrlc_version}), $fh); 115 } 116 } 117 $self->fsl_glows::write($fh); 118 if (defined $self->{fsl_visuals}->{raw_data}) { 119 $self->fsl_visuals::write($fh); 120 } elsif (defined $self->{compressed}->{chunks::get_index('FSL_VISUALS', $self->{fsl_header}->{xrlc_version})}) { 121 $self->compressed::write(chunks::get_index('FSL_VISUALS', $self->{fsl_header}->{xrlc_version}), $fh); 122 } 123 if (defined $self->{fsl_vertex_buffer}->{raw_data}) { 124 $self->fsl_vertex_buffer::write($fh); 125 } elsif (chunks::get_index('FSL_VB', $self->{fsl_header}->{xrlc_version}) && defined $self->{compressed}->{chunks::get_index('FSL_VB', $self->{fsl_header}->{xrlc_version})}) { 126 $self->compressed::write(chunks::get_index('FSL_VB', $self->{fsl_header}->{xrlc_version}), $fh); 127 } elsif (defined $self->{compressed}->{chunks::get_index('FSL_VB_OLD', $self->{fsl_header}->{xrlc_version})}) { 128 $self->compressed::write(chunks::get_index('FSL_VB_OLD', $self->{fsl_header}->{xrlc_version}), $fh); 129 } 130 if ($self->{fsl_header}->{xrlc_version} >= 12) { 131 if (defined $self->{fsl_swis}->{raw_data}) { 132 $self->fsl_swis::write($fh); 133 } elsif (defined $self->{compressed}->{11}) { 134 $self->compressed::write(11, $fh); 135 } 136 } 137 if (defined $self->{fsl_index_buffer}->{raw_data}) { 138 $self->fsl_index_buffer::write($fh); 139 } elsif (chunks::get_index('FSL_IB', $self->{fsl_header}->{xrlc_version}) && defined $self->{compressed}->{chunks::get_index('FSL_IB', $self->{fsl_header}->{xrlc_version})}) { 140 $self->compressed::write(chunks::get_index('FSL_IB', $self->{fsl_header}->{xrlc_version}), $fh); 141 } 142 if (defined $self->{fsl_textures}->{count}) { 143 $self->fsl_textures::write($fh); 144 } 145 $self->fsl_shaders::write($fh); 146 if (defined $self->{fsl_sectors}->{raw_data}) { 147 $self->fsl_sectors::write($fh); 148 } elsif (defined $self->{compressed}->{chunks::get_index('FSL_SECTORS', $self->{fsl_header}->{xrlc_version})}) { 149 $self->compressed::write(chunks::get_index('FSL_SECTORS', $self->{fsl_header}->{xrlc_version}), $fh); 150 } 151} 152sub import { 153 my $self = shift; 154 my $imf = stkutils::ini_file->new('FSL_HEADER.ltx', 'r'); 155 $self->fsl_header::import($imf); 156 $imf->close(); 157 $imf = stkutils::ini_file->new('FSL_SHADERS.ltx', 'r'); 158 $self->fsl_shaders::import($imf); 159 $imf->close(); 160 $imf = stkutils::ini_file->new('FSL_LIGHT_DYNAMIC.ltx', 'r'); 161 $self->fsl_light_dynamic::import($imf); 162 $imf->close(); 163 $imf = stkutils::ini_file->new('FSL_GLOWS.ltx', 'r'); 164 $self->fsl_glows::import($imf); 165 $imf->close(); 166 if ($imf = IO::File->new('FSL_VISUALS.bin', 'r')) { 167 binmode $imf; 168 $self->fsl_visuals::import($imf); 169 $imf->close(); 170 } 171 if ($imf = IO::File->new('FSL_PORTALS.bin', 'r')) { 172 binmode $imf; 173 $self->fsl_portals::import($imf); 174 $imf->close(); 175 } 176 if ($imf = IO::File->new('FSL_CFORM.bin', 'r')) { 177 binmode $imf; 178 $self->fsl_cform::import($imf); 179 $imf->close(); 180 } 181 if ($imf = stkutils::ini_file->new('FSL_TEXTURES.ltx', 'r')) { 182 $self->fsl_textures::import($imf); 183 $imf->close(); 184 } 185 if ($imf = IO::File->new('FSL_LIGHT_KEY_FRAMES.bin', 'r')) { 186 binmode $imf; 187 $self->fsl_light_key_frames::import($imf); 188 $imf->close(); 189 } 190 if ($imf = IO::File->new('FSL_SHADER_CONSTANT.bin', 'r')) { 191 binmode $imf; 192 $self->fsl_shader_constant::import($imf); 193 $imf->close(); 194 } 195 if ($imf = IO::File->new('FSL_SECTORS.bin', 'r')) { 196 binmode $imf; 197 $self->fsl_sectors::import($imf); 198 $imf->close(); 199 } 200 if ($imf = IO::File->new('FSL_VERTEX_BUFFER.bin', 'r')) { 201 binmode $imf; 202 $self->fsl_vertex_buffer::import($imf); 203 $imf->close(); 204 } 205 if ($imf = IO::File->new('FSL_INDEX_BUFFER.bin', 'r')) { 206 binmode $imf; 207 $self->fsl_index_buffer::import($imf); 208 $imf->close(); 209 } 210 if ($imf = IO::File->new('FSL_SWIS.bin', 'r')) { 211 binmode $imf; 212 $self->fsl_swis::import($imf); 213 $imf->close(); 214 } 215 my ($dirhandle, $compressed); 216 opendir $dirhandle, getcwd() or die; 217 while ($compressed = readdir $dirhandle) { 218 if ($compressed =~ /^(COMPRESSED_)(\w+)(.bin)$/) { 219 my $imf = IO::File->new($compressed, 'r'); 220 binmode $imf; 221 $self->compressed::import($imf, $2); 222 $imf->close(); 223 } 224 } 225 closedir $dirhandle; 226} 227sub export { 228 my $self = shift; 229 my $outf = IO::File->new('FSL_HEADER.ltx', 'w'); 230 $self->fsl_header::export($outf); 231 $outf->close(); 232 $outf = IO::File->new('FSL_SHADERS.ltx', 'w'); 233 $self->fsl_shaders::export($outf); 234 $outf->close(); 235 $outf = IO::File->new('FSL_LIGHT_DYNAMIC.ltx', 'w'); 236 $self->fsl_light_dynamic::export($outf); 237 $outf->close(); 238 $outf = IO::File->new('FSL_GLOWS.ltx', 'w'); 239 $self->fsl_glows::export($outf); 240 $outf->close(); 241 if (defined $self->{fsl_textures}->{count}) { 242 $outf = IO::File->new('FSL_TEXTURES.ltx', 'w'); 243 $self->fsl_textures::export($outf); 244 $outf->close(); 245 } 246 if (defined $self->{fsl_cform}->{raw_data}) { 247 $outf = IO::File->new('FSL_CFORM.bin', 'w'); 248 $self->fsl_cform::export($outf); 249 $outf->close(); 250 } 251 if (defined $self->{fsl_shader_constant}->{raw_data}) { 252 $outf = IO::File->new('FSL_SHADER_CONSTANT.bin', 'w'); 253 $self->fsl_shader_constant::export($outf); 254 $outf->close(); 255 } 256 if (defined $self->{fsl_light_key_frames}->{raw_data}) { 257 $outf = IO::File->new('FSL_LIGHT_KEY_FRAMES.bin', 'w'); 258 $self->fsl_light_key_frames::export($outf); 259 $outf->close(); 260 } 261 if (defined $self->{fsl_visuals}->{raw_data}) { 262 $outf = IO::File->new('FSL_VISUALS.bin', 'w'); 263 $self->fsl_visuals::export($outf); 264 $outf->close(); 265 } 266 if (defined $self->{fsl_portals}->{raw_data}) { 267 $outf = IO::File->new('FSL_PORTALS.bin', 'w'); 268 $self->fsl_portals::export($outf); 269 $outf->close(); 270 } 271 if (defined $self->{fsl_sectors}->{raw_data}) { 272 $outf = IO::File->new('FSL_SECTORS.bin', 'w'); 273 $self->fsl_sectors::export($outf); 274 $outf->close(); 275 } 276 if (defined $self->{fsl_vertex_buffer}->{raw_data}) { 277 $outf = IO::File->new('FSL_VERTEX_BUFFER.bin', 'w'); 278 $self->fsl_vertex_buffer::export($outf); 279 $outf->close(); 280 } 281 if (defined $self->{fsl_index_buffer}->{raw_data}) { 282 $outf = IO::File->new('FSL_INDEX_BUFFER.bin', 'w'); 283 $self->fsl_index_buffer::export($outf); 284 $outf->close(); 285 } 286 if (defined $self->{fsl_swis}->{raw_data}) { 287 $outf = IO::File->new('FSL_SWIS.bin', 'w'); 288 $self->fsl_swis::export($outf); 289 $outf->close(); 290 } 291 if (defined $self->{compressed}) { 292 $self->compressed::export(); 293 } 294} 295########################################################### 296package fsl_header; 297use strict; 298use stkutils::data_packet; 299use stkutils::chunked_file; 300sub read { 301 my $self = shift; 302 my ($data) = @_; 303 my $packet = stkutils::data_packet->new($data); 304 ($self->{fsl_header}->{xrlc_version}, $self->{fsl_header}->{xrlc_quality}) = $packet->unpack('vv'); 305 if ($self->{fsl_header}->{xrlc_version} < 11) { 306 @{$self->{fsl_header}->{name}} = $packet->unpack('Z*'); 307 } else { 308 die unless $packet->length() == 0; 309 } 310} 311sub write { 312 my $self = shift; 313 my ($cf) = @_; 314 if ($self->{fsl_header}->{xrlc_version} > 10) { 315 $cf->w_chunk(1, pack('vv', $self->{fsl_header}->{xrlc_version}, $self->{fsl_header}->{xrlc_quality})); 316 } else { 317 my $l = length($self->{fsl_header}->{name}); 318 my $zc = 123 - $l; 319 $cf->w_chunk_open(1); 320 $cf->w_chunk_data(pack('vvZ*', $self->{fsl_header}->{xrlc_version}, $self->{fsl_header}->{xrlc_quality}, $self->{fsl_header}->{name})); 321 for (my $i = 0; $i < $zc; $i++) { 322 $cf->w_chunk_data(pack('C', 0)); 323 } 324 $cf->w_chunk_close(); 325 } 326} 327sub export { 328 my $self = shift; 329 my ($cf) = @_; 330 331 print $cf "[header]\n"; 332 print $cf "xrLC version = $self->{fsl_header}->{xrlc_version}\n"; 333 print $cf "xrLC quality = $self->{fsl_header}->{xrlc_quality}\n"; 334 print $cf "name = $self->{fsl_header}->{name}[0]\n" if $self->{fsl_header}->{xrlc_version} < 11; 335} 336sub import { 337 my $self = shift; 338 my ($cf) = @_; 339 $self->{fsl_header}->{xrlc_version} = $cf->value('header', 'xrLC version'); 340 $self->{fsl_header}->{xrlc_quality} = $cf->value('header', 'xrLC quality'); 341 $self->{fsl_header}->{name} = $cf->value('header', 'name') if $self->{fsl_header}->{xrlc_version} < 11; 342} 343######################################################### 344package fsl_shaders; 345use strict; 346use stkutils::data_packet; 347sub read { 348 my $self = shift; 349 my ($data) = @_; 350 my $packet = stkutils::data_packet->new($data); 351 ($self->{fsl_shaders}->{count}) = $packet->unpack('V'); 352 @{$self->{fsl_shaders}->{shaders}} = $packet->unpack("(Z*)$self->{fsl_shaders}->{count}"); 353 die unless $packet->length() == 0; 354} 355sub write { 356 my $self = shift; 357 my ($cf) = @_; 358 my $index = chunks::get_index('FSL_SHADERS', $self->{fsl_header}->{xrlc_version}); 359 $cf->w_chunk_open($index); 360 $cf->w_chunk_data(pack('V', $self->{fsl_shaders}->{count})); 361 for (my $i = 0; $i < $self->{fsl_shaders}->{count}; $i++) { 362 $cf->w_chunk_data(pack('Z*', $self->{fsl_shaders}->{shaders}[$i])); 363 } 364 $cf->w_chunk_close(); 365} 366sub export { 367 my $self = shift; 368 my ($cf) = @_; 369 370 for (my $i = 0; $i < $self->{fsl_shaders}->{count}; $i++) { 371 print $cf "[$i]\n"; 372 if ($self->{fsl_header}->{xrlc_version} > 11) { 373 if (!(@{$self->{fsl_shaders}->{shaders}}[$i] eq '')) { 374 my ($shader, $texture) = split '/', @{$self->{fsl_shaders}->{shaders}}[$i]; 375 print $cf "shader = $shader\n"; 376 print $cf "texture = $texture\n\n"; 377 } else { 378 print $cf "shader = @{$self->{fsl_shaders}->{shaders}}[$i]\n"; 379 print $cf "texture = @{$self->{fsl_shaders}->{shaders}}[$i]\n\n"; 380 } 381 } else { 382 print $cf "shader = @{$self->{fsl_shaders}->{shaders}}[$i]\n"; 383 } 384 } 385} 386sub import { 387 my $self = shift; 388 my ($cf) = @_; 389 for (my $i = 0; $i < $#{$cf->{sections_list}} + 1; $i++) { 390 my $shader = $cf->value($i, 'shader'); 391 if ($self->{fsl_header}->{xrlc_version} > 11) { 392 my $texture = $cf->value($i, 'texture'); 393 if (!($shader eq $texture)) { 394 $self->{fsl_shaders}->{shaders}[$i] = join('/', $shader, $texture); 395 } else { 396 $self->{fsl_shaders}->{shaders}[$i] = $shader; 397 } 398 } else { 399 $self->{fsl_shaders}->{shaders}[$i] = $shader; 400 } 401 } 402 $self->{fsl_shaders}->{count} = $#{$cf->{sections_list}} + 1; 403} 404########################################################### 405package fsl_textures; 406use strict; 407use IO::File; 408sub read { 409 my $self = shift; 410 my ($data) = @_; 411 my $packet = stkutils::data_packet->new($data); 412 ($self->{fsl_textures}->{count}) = $packet->unpack('V'); 413 @{$self->{fsl_textures}->{textures}} = $packet->unpack("(Z*)$self->{fsl_textures}->{count}"); 414 die unless $packet->length() == 0; 415} 416sub write { 417 my $self = shift; 418 my ($cf) = @_; 419 420 $cf->w_chunk_open(2); 421 $cf->w_chunk_data(pack('V', $self->{fsl_textures}->{count})); 422 for (my $i = 0; $i < $self->{fsl_textures}->{count}; $i++) { 423 $cf->w_chunk_data(pack('Z*', $self->{fsl_textures}->{textures}[$i])); 424 } 425 $cf->w_chunk_close(); 426} 427sub export { 428 my $self = shift; 429 my ($cf) = @_; 430 for (my $i = 0; $i < $self->{fsl_textures}->{count}; $i++) { 431 print $cf "[$i]\n"; 432 print $cf "texture = @{$self->{fsl_textures}->{textures}}[$i]\n"; 433 } 434} 435sub import { 436 my $self = shift; 437 my ($cf) = @_; 438 for (my $i = 0; $i < $#{$cf->{sections_list}} + 1; $i++) { 439 $self->{fsl_textures}->{textures}[$i] = $cf->value($i, 'texture'); 440 } 441 $self->{fsl_textures}->{count} = $#{$cf->{sections_list}} + 1; 442} 443########################################################### 444package fsl_cform; 445use strict; 446use IO::File; 447sub read { 448 my $self = shift; 449 my ($data) = @_; 450 $self->{fsl_cform}->{raw_data} = $data; 451} 452sub write { 453 my $self = shift; 454 my ($cf) = @_; 455 my $index = chunks::get_index('FSL_CFORM', $self->{fsl_header}->{xrlc_version}); 456 $cf->w_chunk($index, $self->{fsl_cform}->{raw_data}); 457} 458sub export { 459 my $self = shift; 460 my ($cf) = @_; 461 binmode $cf; 462 $cf->write($self->{fsl_cform}->{raw_data}, length($self->{fsl_cform}->{raw_data})); 463} 464sub import { 465 my $self = shift; 466 my ($cf) = @_; 467 $cf->read($self->{fsl_cform}->{raw_data}, ($cf->stat())[7]); 468} 469########################################################### 470package fsl_light_key_frames; 471use strict; 472use IO::File; 473sub read { 474 my $self = shift; 475 my ($data) = @_; 476 $self->{fsl_light_key_frames}->{raw_data} = $data; 477} 478sub write { 479 my $self = shift; 480 my ($cf) = @_; 481 $cf->w_chunk(9, $self->{fsl_light_key_frames}->{raw_data}); 482} 483sub export { 484 my $self = shift; 485 my ($cf) = @_; 486 binmode $cf; 487 $cf->write($self->{fsl_light_key_frames}->{raw_data}, length($self->{fsl_light_key_frames}->{raw_data})); 488} 489sub import { 490 my $self = shift; 491 my ($cf) = @_; 492 $cf->read($self->{fsl_light_key_frames}->{raw_data}, ($cf->stat())[7]); 493} 494########################################################### 495package fsl_shader_constant; 496use strict; 497use IO::File; 498sub read { 499 my $self = shift; 500 my ($data) = @_; 501 $self->{fsl_shader_constant}->{raw_data} = $data; 502} 503sub write { 504 my $self = shift; 505 my ($cf) = @_; 506 $cf->w_chunk(7, $self->{fsl_shader_constant}->{raw_data}); 507} 508sub export { 509 my $self = shift; 510 my ($cf) = @_; 511 binmode $cf; 512 $cf->write($self->{fsl_shader_constant}->{raw_data}, length($self->{fsl_shader_constant}->{raw_data})); 513} 514sub import { 515 my $self = shift; 516 my ($cf) = @_; 517 $cf->read($self->{fsl_shader_constant}->{raw_data}, ($cf->stat())[7]); 518} 519########################################################### 520package fsl_visuals; 521use strict; 522use IO::File; 523sub read { 524 my $self = shift; 525 my ($data) = @_; 526 $self->{fsl_visuals}->{raw_data} = $data; 527} 528sub write { 529 my $self = shift; 530 my ($cf) = @_; 531 my $index = chunks::get_index('FSL_VISUALS', $self->{fsl_header}->{xrlc_version}); 532 $cf->w_chunk($index, $self->{fsl_visuals}->{raw_data}); 533} 534sub export { 535 my $self = shift; 536 my ($cf) = @_; 537 binmode $cf; 538 $cf->write($self->{fsl_visuals}->{raw_data}, length($self->{fsl_visuals}->{raw_data})); 539} 540sub import { 541 my $self = shift; 542 my ($cf) = @_; 543 $cf->read($self->{fsl_visuals}->{raw_data}, ($cf->stat())[7]); 544} 545############################################################ 546package fsl_portals; 547use strict; 548use IO::File; 549sub read { 550 my $self = shift; 551 my ($data) = @_; 552 $self->{fsl_portals}->{raw_data} = $data; 553} 554sub write { 555 my $self = shift; 556 my ($cf) = @_; 557 my $index = chunks::get_index('FSL_PORTALS', $self->{fsl_header}->{xrlc_version}); 558 $cf->w_chunk($index, $self->{fsl_portals}->{raw_data}); 559} 560sub export { 561 my $self = shift; 562 my ($cf) = @_; 563 binmode $cf; 564 $cf->write($self->{fsl_portals}->{raw_data}, length($self->{fsl_portals}->{raw_data})); 565} 566sub import { 567 my $self = shift; 568 my ($cf) = @_; 569 $cf->read($self->{fsl_portals}->{raw_data}, ($cf->stat())[7]); 570} 571########################################################### 572package fsl_light_dynamic; 573use strict; 574use IO::File; 575use constant lt_names => { 576 1 => 'point', 577 2 => 'spot', 578 3 => 'directional', 579}; 580use constant reverse_lt_names => { 581 'point' => 1, 582 'spot' => 2, 583 'directional' => 3, 584}; 585sub read { 586 my $self = shift; 587 my ($data) = @_; 588 my $packet = stkutils::data_packet->new($data); 589 if ($self->{fsl_header}->{xrlc_version} > 8) { 590 $self->{fsl_light_dynamic}->{count} = $packet->length() / 0x6c; 591 die unless $packet->length() % 0x6c == 0; 592 for (my $i = 0; $i < $self->{fsl_light_dynamic}->{count}; $i++) { 593 ($self->{fsl_light_dynamic}->{$i}{controller_id}, 594 $self->{fsl_light_dynamic}->{$i}{type}) = $packet->unpack('VV'); 595 @{$self->{fsl_light_dynamic}->{$i}{diffuse}} = $packet->unpack('f4'); 596 @{$self->{fsl_light_dynamic}->{$i}{specular}} = $packet->unpack('f4'); 597 @{$self->{fsl_light_dynamic}->{$i}{ambient}} = $packet->unpack('f4'); 598 @{$self->{fsl_light_dynamic}->{$i}{position}} = $packet->unpack('f3'); 599 @{$self->{fsl_light_dynamic}->{$i}{direction}} = $packet->unpack('f3'); 600 @{$self->{fsl_light_dynamic}->{$i}{other}} = $packet->unpack('f7'); 601 } 602 die unless $packet->length() == 0; 603 } elsif ($self->{fsl_header}->{xrlc_version} > 5) { 604 $self->{fsl_light_dynamic}->{count} = $packet->length() / 0xB0; 605 die unless $packet->length() % 0xB0 == 0; 606 for (my $i = 0; $i < $self->{fsl_light_dynamic}->{count}; $i++) { 607 $self->{fsl_light_dynamic}->{$i}{type} = $packet->unpack('V'); 608 @{$self->{fsl_light_dynamic}->{$i}{diffuse}} = $packet->unpack('f4'); 609 @{$self->{fsl_light_dynamic}->{$i}{specular}} = $packet->unpack('f4'); 610 @{$self->{fsl_light_dynamic}->{$i}{ambient}} = $packet->unpack('f4'); 611 @{$self->{fsl_light_dynamic}->{$i}{position}} = $packet->unpack('f3'); 612 @{$self->{fsl_light_dynamic}->{$i}{direction}} = $packet->unpack('f3'); 613 @{$self->{fsl_light_dynamic}->{$i}{other}} = $packet->unpack('f7'); 614 ($self->{fsl_light_dynamic}->{$i}{unk1}, 615 $self->{fsl_light_dynamic}->{$i}{unk2}, 616 $self->{fsl_light_dynamic}->{$i}{name}) = $packet->unpack('VVZ*'); 617 my $l = 63 - length($self->{fsl_light_dynamic}->{$i}{name}); 618 $self->{fsl_light_dynamic}->{$i}{garb} = $packet->unpack("C$l"); 619 } 620 die unless $packet->length() == 0; 621 } else { 622 $self->{fsl_light_dynamic}->{count} = $packet->length() / 0x7c; 623 die unless $packet->length() % 0x7c == 0; 624 for (my $i = 0; $i < $self->{fsl_light_dynamic}->{count}; $i++) { 625 $self->{fsl_light_dynamic}->{$i}{type} = $packet->unpack('V'); 626 @{$self->{fsl_light_dynamic}->{$i}{diffuse}} = $packet->unpack('f4'); 627 @{$self->{fsl_light_dynamic}->{$i}{specular}} = $packet->unpack('f4'); 628 @{$self->{fsl_light_dynamic}->{$i}{ambient}} = $packet->unpack('f4'); 629 @{$self->{fsl_light_dynamic}->{$i}{position}} = $packet->unpack('f3'); 630 @{$self->{fsl_light_dynamic}->{$i}{direction}} = $packet->unpack('f3'); 631 @{$self->{fsl_light_dynamic}->{$i}{other}} = $packet->unpack('f7'); 632 @{$self->{fsl_light_dynamic}->{$i}{unk}} = $packet->unpack('V5'); 633 } 634 die unless $packet->length() == 0; 635 } 636} 637sub write { 638 my $self = shift; 639 my ($cf) = @_; 640 my $index = chunks::get_index('FSL_LIGHT_DYNAMIC', $self->{fsl_header}->{xrlc_version}); 641 $cf->w_chunk_open($index); 642 if ($self->{fsl_header}->{xrlc_version} > 8) { 643 for (my $i = 0; $i < $self->{fsl_light_dynamic}->{count}; $i++) { 644 $cf->w_chunk_data(pack('VVf4f4f4f3f3f7', $self->{fsl_light_dynamic}->{$i}{controller_id}, $self->{fsl_light_dynamic}->{$i}{type}, @{$self->{fsl_light_dynamic}->{$i}{diffuse}}, @{$self->{fsl_light_dynamic}->{$i}{specular}}, @{$self->{fsl_light_dynamic}->{$i}{ambient}}, @{$self->{fsl_light_dynamic}->{$i}{position}}, @{$self->{fsl_light_dynamic}->{$i}{direction}}, @{$self->{fsl_light_dynamic}->{$i}{other}})); 645 } 646 } elsif ($self->{fsl_header}->{xrlc_version} > 5) { 647 for (my $i = 0; $i < $self->{fsl_light_dynamic}->{count}; $i++) { 648 $cf->w_chunk_data(pack('Vf4f4f4f3f3f7VVZ*', $self->{fsl_light_dynamic}->{$i}{type}, @{$self->{fsl_light_dynamic}->{$i}{diffuse}}, @{$self->{fsl_light_dynamic}->{$i}{specular}}, @{$self->{fsl_light_dynamic}->{$i}{ambient}}, @{$self->{fsl_light_dynamic}->{$i}{position}}, @{$self->{fsl_light_dynamic}->{$i}{direction}}, @{$self->{fsl_light_dynamic}->{$i}{other}}, $self->{fsl_light_dynamic}->{$i}{unk1}, $self->{fsl_light_dynamic}->{$i}{unk2}, $self->{fsl_light_dynamic}->{$i}{name})); 649 for (my $i = 0; $i < (64 - length($self->{fsl_light_dynamic}->{$i}{name})); $i++) { 650 $cf->w_chunk_data(pack('C', 0xED)); 651 } 652 } 653 } else { 654 for (my $i = 0; $i < $self->{fsl_light_dynamic}->{count}; $i++) { 655 $cf->w_chunk_data(pack('Vf4f4f4f3f3f7V5', $self->{fsl_light_dynamic}->{$i}{type}, @{$self->{fsl_light_dynamic}->{$i}{diffuse}}, @{$self->{fsl_light_dynamic}->{$i}{specular}}, @{$self->{fsl_light_dynamic}->{$i}{ambient}}, @{$self->{fsl_light_dynamic}->{$i}{position}}, @{$self->{fsl_light_dynamic}->{$i}{direction}}, @{$self->{fsl_light_dynamic}->{$i}{other}}, @{$self->{fsl_light_dynamic}->{$i}{unk}})); 656 } 657 } 658 $cf->w_chunk_close(); 659} 660sub export { 661 my $self = shift; 662 my ($cf) = @_; 663 for (my $i = 0; $i < $self->{fsl_light_dynamic}->{count}; $i++) { 664 print $cf "[$i]\n"; 665 print $cf "controller_id = $self->{fsl_light_dynamic}->{$i}{controller_id}\n" if defined $self->{fsl_light_dynamic}->{$i}{controller_id}; 666 printf $cf "type = %s\n", lt_names->{$self->{fsl_light_dynamic}->{$i}{type}}; 667 printf $cf "diffuse = %f, %f, %f, %f\n", @{$self->{fsl_light_dynamic}->{$i}{diffuse}}; 668 printf $cf "specular = %f, %f, %f, %f\n", @{$self->{fsl_light_dynamic}->{$i}{specular}}; 669 printf $cf "ambient = %f, %f, %f, %f\n", @{$self->{fsl_light_dynamic}->{$i}{ambient}}; 670 printf $cf "position = %f, %f, %f\n", @{$self->{fsl_light_dynamic}->{$i}{position}}; 671 printf $cf "direction = %f, %f, %f\n", @{$self->{fsl_light_dynamic}->{$i}{direction}}; 672 printf $cf "range = %f\n", @{$self->{fsl_light_dynamic}->{$i}{other}}[0]; 673 printf $cf "falloff = %f\n", @{$self->{fsl_light_dynamic}->{$i}{other}}[1]; 674 printf $cf "attenuation0 = %f\n", @{$self->{fsl_light_dynamic}->{$i}{other}}[2]; 675 printf $cf "attenuation1 = %f\n", @{$self->{fsl_light_dynamic}->{$i}{other}}[3]; 676 printf $cf "attenuation2 = %f\n", @{$self->{fsl_light_dynamic}->{$i}{other}}[4]; 677 printf $cf "theta = %f\n", @{$self->{fsl_light_dynamic}->{$i}{other}}[5]; 678 printf $cf "phi = %f\n", @{$self->{fsl_light_dynamic}->{$i}{other}}[6]; 679 print $cf "unk1 = $self->{fsl_light_dynamic}->{$i}{unk1}\n" if defined $self->{fsl_light_dynamic}->{$i}{unk1}; 680 print $cf "unk2 = $self->{fsl_light_dynamic}->{$i}{unk2}\n" if defined $self->{fsl_light_dynamic}->{$i}{unk2}; 681 print $cf "name = $self->{fsl_light_dynamic}->{$i}{name}\n" if defined $self->{fsl_light_dynamic}->{$i}{name}; 682 if (defined @{$self->{fsl_light_dynamic}->{$i}{unk}}) { 683 printf $cf "unk_0 = %s\n", @{$self->{fsl_light_dynamic}->{$i}{unk}}[0]; 684 printf $cf "unk_1 = %s\n", @{$self->{fsl_light_dynamic}->{$i}{unk}}[1]; 685 printf $cf "unk_2 = %s\n", @{$self->{fsl_light_dynamic}->{$i}{unk}}[2]; 686 printf $cf "unk_3 = %s\n", @{$self->{fsl_light_dynamic}->{$i}{unk}}[3]; 687 printf $cf "unk_4 = %s\n", @{$self->{fsl_light_dynamic}->{$i}{unk}}[4]; 688 } 689 print "\n"; 690 } 691} 692sub import { 693 my $self = shift; 694 my ($cf) = @_; 695 for (my $i = 0; $i < $#{$cf->{sections_list}} + 1; $i++) { 696 $self->{fsl_light_dynamic}->{$i}{controller_id} = $cf->value($i, 'controller_id'); 697 $self->{fsl_light_dynamic}->{$i}{type} = reverse_lt_names->{$cf->value($i, 'type')}; 698 @{$self->{fsl_light_dynamic}->{$i}{diffuse}} = split(',', $cf->value($i, 'diffuse')); 699 @{$self->{fsl_light_dynamic}->{$i}{specular}} = split(',', $cf->value($i, 'specular')); 700 @{$self->{fsl_light_dynamic}->{$i}{ambient}} = split(',', $cf->value($i, 'ambient')); 701 @{$self->{fsl_light_dynamic}->{$i}{position}} = split(',', $cf->value($i, 'position')); 702 @{$self->{fsl_light_dynamic}->{$i}{direction}} = split(',', $cf->value($i, 'direction')); 703 $self->{fsl_light_dynamic}->{$i}{other}[0] = $cf->value($i, 'range'); 704 $self->{fsl_light_dynamic}->{$i}{other}[1] = $cf->value($i, 'falloff'); 705 $self->{fsl_light_dynamic}->{$i}{other}[2] = $cf->value($i, 'attenuation0'); 706 $self->{fsl_light_dynamic}->{$i}{other}[3] = $cf->value($i, 'attenuation1'); 707 $self->{fsl_light_dynamic}->{$i}{other}[4] = $cf->value($i, 'attenuation2'); 708 $self->{fsl_light_dynamic}->{$i}{other}[5] = $cf->value($i, 'theta'); 709 $self->{fsl_light_dynamic}->{$i}{other}[6] = $cf->value($i, 'phi'); 710 $self->{fsl_light_dynamic}->{$i}{unk1} = $cf->value($i, 'unk1'); 711 $self->{fsl_light_dynamic}->{$i}{unk2} = $cf->value($i, 'unk2'); 712 $self->{fsl_light_dynamic}->{$i}{name} = $cf->value($i, 'name'); 713 $self->{fsl_light_dynamic}->{$i}{unk}[0] = $cf->value($i, 'unk_0'); 714 $self->{fsl_light_dynamic}->{$i}{unk}[1] = $cf->value($i, 'unk_1'); 715 $self->{fsl_light_dynamic}->{$i}{unk}[2] = $cf->value($i, 'unk_2'); 716 $self->{fsl_light_dynamic}->{$i}{unk}[3] = $cf->value($i, 'unk_3'); 717 $self->{fsl_light_dynamic}->{$i}{unk}[4] = $cf->value($i, 'unk_4'); 718 } 719 $self->{fsl_light_dynamic}->{count} = $#{$cf->{sections_list}} + 1; 720} 721########################################################### 722package fsl_glows; 723use strict; 724use IO::File; 725sub read { 726 my $self = shift; 727 my ($data) = @_; 728 my $packet = stkutils::data_packet->new($data); 729 if ($self->{fsl_header}->{xrlc_version} > 11) { 730 $self->{fsl_glows}->{count} = $packet->length() / 0x12; 731 die unless $packet->length() % 0x12 == 0; 732 } else { 733 $self->{fsl_glows}->{count} = $packet->length() / 0x18; 734 die unless $packet->length() % 0x18 == 0; 735 } 736 for (my $i = 0; $i < $self->{fsl_glows}->{count}; $i++) { 737 (${$self->{fsl_glows}->{$i}{position}}[0], 738 ${$self->{fsl_glows}->{$i}{position}}[1], 739 ${$self->{fsl_glows}->{$i}{position}}[2], 740 $self->{fsl_glows}->{$i}{radius}) = $packet->unpack('ffff'); 741 if ($self->{fsl_header}->{xrlc_version} <= 11) { 742 ($self->{fsl_glows}->{$i}{texture_index}, 743 $self->{fsl_glows}->{$i}{shader_index}) = $packet->unpack('VV'); 744 } else { 745 $self->{fsl_glows}->{$i}{shader_index} = $packet->unpack('v'); 746 } 747 } 748 die unless $packet->length() == 0; 749} 750sub write { 751 my $self = shift; 752 my ($cf) = @_; 753 my $index = chunks::get_index('FSL_GLOWS', $self->{fsl_header}->{xrlc_version}); 754 $cf->w_chunk_open($index); 755 if ($self->{fsl_header}->{xrlc_version} <= 11) { 756 for (my $i = 0; $i < $self->{fsl_glows}->{count}; $i++) { 757 $cf->w_chunk_data(pack('f3fVV', @{$self->{fsl_glows}->{$i}{position}}, $self->{fsl_glows}->{$i}{radius}, $self->{fsl_glows}->{$i}{texture_index}, $self->{fsl_glows}->{$i}{shader_index})); 758 } 759 } else { 760 for (my $i = 0; $i < $self->{fsl_glows}->{count}; $i++) { 761 $cf->w_chunk_data(pack('f3fv', @{$self->{fsl_glows}->{$i}{position}}, $self->{fsl_glows}->{$i}{radius}, $self->{fsl_glows}->{$i}{shader_index})); 762 } 763 764 } 765 $cf->w_chunk_close(); 766} 767sub export { 768 my $self = shift; 769 my ($cf) = @_; 770 771 for (my $i = 0; $i < $self->{fsl_glows}->{count}; $i++) { 772 print $cf "[$i]\n"; 773 printf $cf "position = %f,%f,%f\n", @{$self->{fsl_glows}->{$i}{position}}[0..2]; 774 printf $cf "radius = %f\n", $self->{fsl_glows}->{$i}{radius}; 775 print $cf "texture_index = $self->{fsl_glows}->{$i}{texture_index}\n" if $self->{fsl_header}->{xrlc_version} <= 11; 776 print $cf "shader_index = $self->{fsl_glows}->{$i}{shader_index}\n\n"; 777 } 778} 779sub import { 780 my $self = shift; 781 my ($cf) = @_; 782 for (my $i = 0; $i < $#{$cf->{sections_list}} + 1; $i++) { 783 @{$self->{fsl_glows}->{$i}{position}} = split(',', $cf->value($i, 'position')); 784 $self->{fsl_glows}->{$i}{radius} = $cf->value($i, 'radius'); 785 $self->{fsl_glows}->{$i}{texture_index} = $cf->value($i, 'texture_index') if $self->{fsl_header}->{xrlc_version} <= 11; 786 $self->{fsl_glows}->{$i}{shader_index} = $cf->value($i, 'shader_index'); 787 } 788 $self->{fsl_glows}->{count} = $#{$cf->{sections_list}} + 1; 789} 790########################################################### 791package fsl_sectors; 792use strict; 793use IO::File; 794sub read { 795 my $self = shift; 796 my ($data) = @_; 797 $self->{fsl_sectors}->{raw_data} = $data; 798} 799sub write { 800 my $self = shift; 801 my ($cf) = @_; 802 my $index = chunks::get_index('FSL_SECTORS', $self->{fsl_header}->{xrlc_version}); 803 $cf->w_chunk($index, $self->{fsl_sectors}->{raw_data}); 804} 805sub export { 806 my $self = shift; 807 my ($cf) = @_; 808 binmode $cf; 809 $cf->write($self->{fsl_sectors}->{raw_data}, length($self->{fsl_sectors}->{raw_data})); 810} 811sub import { 812 my $self = shift; 813 my ($cf) = @_; 814 $cf->read($self->{fsl_sectors}->{raw_data}, ($cf->stat())[7]); 815} 816########################################################### 817package fsl_vertex_buffer; 818use strict; 819use IO::File; 820sub read { 821 my $self = shift; 822 my ($data) = @_; 823 $self->{fsl_vertex_buffer}->{raw_data} = $data; 824} 825sub write { 826 my $self = shift; 827 my ($cf) = @_; 828 my $index = chunks::get_index('FSL_VB', $self->{fsl_header}->{xrlc_version}); 829 $cf->w_chunk($index, $self->{fsl_vertex_buffer}->{raw_data}); 830} 831sub export { 832 my $self = shift; 833 my ($cf) = @_; 834 binmode $cf; 835 $cf->write($self->{fsl_vertex_buffer}->{raw_data}, length($self->{fsl_vertex_buffer}->{raw_data})); 836} 837sub import { 838 my $self = shift; 839 my ($cf) = @_; 840 $cf->read($self->{fsl_vertex_buffer}->{raw_data}, ($cf->stat())[7]); 841} 842########################################################### 843package fsl_index_buffer; 844use strict; 845use IO::File; 846sub read { 847 my $self = shift; 848 my ($data) = @_; 849 $self->{fsl_index_buffer}->{raw_data} = $data; 850} 851sub write { 852 my $self = shift; 853 my ($cf) = @_; 854 my $index = chunks::get_index('FSL_IB', $self->{fsl_header}->{xrlc_version}); 855 $cf->w_chunk($index, $self->{fsl_index_buffer}->{raw_data}); 856} 857sub export { 858 my $self = shift; 859 my ($cf) = @_; 860 binmode $cf; 861 $cf->write($self->{fsl_index_buffer}->{raw_data}, length($self->{fsl_index_buffer}->{raw_data})); 862} 863sub import { 864 my $self = shift; 865 my ($cf) = @_; 866 $cf->read($self->{fsl_index_buffer}->{raw_data}, ($cf->stat())[7]); 867} 868########################################################### 869package fsl_swis; 870use strict; 871use IO::File; 872sub read { 873 my $self = shift; 874 my ($data) = @_; 875 $self->{fsl_swis}->{raw_data} = $data; 876} 877sub write { 878 my $self = shift; 879 my ($cf) = @_; 880 $cf->w_chunk(11, $self->{fsl_swis}->{raw_data}); 881} 882sub export { 883 my $self = shift; 884 my ($cf) = @_; 885 binmode $cf; 886 $cf->write($self->{fsl_swis}->{raw_data}, length($self->{fsl_swis}->{raw_data})); 887} 888sub import { 889 my $self = shift; 890 my ($cf) = @_; 891 $cf->read($self->{fsl_swis}->{raw_data}, ($cf->stat())[7]); 892} 893########################################################### 894package compressed; 895use strict; 896use IO::File; 897sub read { 898 my $self = shift; 899 my ($index, $data) = @_; 900 $self->{compressed}->{$index} = $data; 901} 902sub write { 903 my $self = shift; 904 my ($index, $cf) = @_; 905 my $ind = 0x80000000 + $index; 906 $cf->w_chunk($ind, $self->{compressed}->{$index}); 907} 908sub export { 909 my $self = shift; 910 for (my $i = 0; $i < 13; $i++) { 911 if (defined $self->{compressed}->{$i}) { 912 my $outf = IO::File->new('COMPRESSED_'.chunks::get_name($i, $self->{fsl_header}->{xrlc_version}).'.bin', 'w'); 913 binmode $outf; 914 $outf->write($self->{compressed}->{$i}, length($self->{compressed}->{$i})); 915 $outf->close(); 916 } 917 } 918} 919sub import { 920 my $self = shift; 921 my ($cf, $name) = @_; 922 $cf->read($self->{compressed}->{chunks::get_index($name, $self->{fsl_header}->{xrlc_version})}, ($cf->stat())[7]); 923} 924########################################################### 925package chunks; 926use constant chunk_table => ( 927 {name => 'FSL_HEADER', version => 0, chunk_index => 0x1}, 928 {name => 'FSL_TEXTURES', version => 0, chunk_index => 0x2}, 929 {name => 'FSL_SHADERS', version => 5, chunk_index => 0x2}, 930 {name => 'FSL_SHADERS', version => 0, chunk_index => 0x3}, 931 {name => 'FSL_VISUALS', version => 5, chunk_index => 0x3}, 932 {name => 'FSL_VISUALS', version => 0, chunk_index => 0x4}, 933 {name => 'FSL_PORTALS', version => 9, chunk_index => 0x4}, 934 {name => 'FSL_PORTALS', version => 5, chunk_index => 0x6}, 935 {name => 'FSL_PORTALS', version => 0, chunk_index => 0x7}, 936 {name => 'FSL_CFORM', version => 5, chunk_index => 0x5}, 937 {name => 'FSL_CFORM', version => 0, chunk_index => 0x6}, 938 {name => 'FSL_SHADER_CONSTANT', version => 8, chunk_index => 0x7}, 939 {name => 'FSL_LIGHT_KEY_FRAMES', version => 0, chunk_index => 0x9}, 940 {name => 'FSL_LIGHT_DYNAMIC', version => 9, chunk_index => 0x6}, 941 {name => 'FSL_LIGHT_DYNAMIC', version => 8, chunk_index => 0x8}, 942 {name => 'FSL_LIGHT_DYNAMIC', version => 5, chunk_index => 0x7}, 943 {name => 'FSL_LIGHT_DYNAMIC', version => 0, chunk_index => 0x8}, 944 {name => 'FSL_GLOWS', version => 9, chunk_index => 0x7}, 945 {name => 'FSL_GLOWS', version => 5, chunk_index => 0x9}, 946 {name => 'FSL_GLOWS', version => 0, chunk_index => 0xa}, 947 {name => 'FSL_SECTORS', version => 9, chunk_index => 0x8}, 948 {name => 'FSL_SECTORS', version => 5, chunk_index => 0xa}, 949 {name => 'FSL_SECTORS', version => 0, chunk_index => 0xb}, 950 {name => 'FSL_VB', version => 12, chunk_index => 0x9}, 951 {name => 'FSL_VB', version => 9, chunk_index => 0xa}, 952 {name => 'FSL_VB', version => 8, chunk_index => 0xc}, 953 {name => 'FSL_VB_OLD', version => 5, chunk_index => 0x4}, 954 {name => 'FSL_VB_OLD', version => 0, chunk_index => 0x5}, 955 {name => 'FSL_IB', version => 12, chunk_index => 0xa}, 956 {name => 'FSL_IB', version => 9, chunk_index => 0x9}, 957 {name => 'FSL_IB', version => 8, chunk_index => 0xb}, 958 {name => 'FSL_SWIS', version => 9, chunk_index => 0xb}, 959); 960use constant reverse_chunk_table => ( 961 {name => 'FSL_HEADER', version => 0, chunk_index => 0x1}, 962 {name => 'FSL_SHADERS', version => 5, chunk_index => 0x2}, 963 {name => 'FSL_TEXTURES', version => 0, chunk_index => 0x2}, 964 {name => 'FSL_VISUALS', version => 5, chunk_index => 0x3}, 965 {name => 'FSL_SHADERS', version => 0, chunk_index => 0x3}, 966 {name => 'FSL_PORTALS', version => 9, chunk_index => 0x4}, 967 {name => 'FSL_VB_OLD', version => 5, chunk_index => 0x4}, 968 {name => 'FSL_VISUALS', version => 0, chunk_index => 0x4}, 969 {name => 'FSL_CFORM', version => 5, chunk_index => 0x5}, 970 {name => 'FSL_VB_OLD', version => 0, chunk_index => 0x5}, 971 {name => 'FSL_LIGHT_DYNAMIC', version => 9, chunk_index => 0x6}, 972 {name => 'FSL_PORTALS', version => 5, chunk_index => 0x6}, 973 {name => 'FSL_CFORM', version => 0, chunk_index => 0x6}, 974 {name => 'FSL_GLOWS', version => 9, chunk_index => 0x7}, 975 {name => 'FSL_SHADER_CONSTANT', version => 8, chunk_index => 0x7}, 976 {name => 'FSL_LIGHT_DYNAMIC', version => 5, chunk_index => 0x7}, 977 {name => 'FSL_PORTALS', version => 0, chunk_index => 0x7}, 978 {name => 'FSL_SECTORS', version => 9, chunk_index => 0x8}, 979 {name => 'FSL_LIGHT_DYNAMIC', version => 8, chunk_index => 0x8}, 980 {name => 'FSL_LIGHT_DYNAMIC', version => 0, chunk_index => 0x8}, 981 {name => 'FSL_VB', version => 12, chunk_index => 0x9}, 982 {name => 'FSL_IB', version => 9, chunk_index => 0x9}, 983 {name => 'FSL_GLOWS', version => 5, chunk_index => 0x9}, 984 {name => 'FSL_LIGHT_KEY_FRAMES', version => 0, chunk_index => 0x9}, 985 {name => 'FSL_IB', version => 12, chunk_index => 0xa}, 986 {name => 'FSL_VB', version => 9, chunk_index => 0xa}, 987 {name => 'FSL_SECTORS', version => 5, chunk_index => 0xa}, 988 {name => 'FSL_GLOWS', version => 0, chunk_index => 0xa}, 989 {name => 'FSL_SWIS', version => 9, chunk_index => 0xb}, 990 {name => 'FSL_IB', version => 5, chunk_index => 0xb}, 991 {name => 'FSL_SECTORS', version => 0, chunk_index => 0xb}, 992 {name => 'FSL_VB', version => 8, chunk_index => 0xc}, 993); 994sub get_index { 995 foreach my $chunk (chunk_table) { 996 if (($_[0] eq $chunk->{name}) && ($_[1] > $chunk->{version})) { 997 return $chunk->{chunk_index}; 998 } 999 } 1000 return undef; 1001} 1002sub get_name { 1003 if ($_[0] & 0x80000000) { 1004 return 'none'; 1005 } 1006 foreach my $chunk (reverse_chunk_table) { 1007 if (($_[0] == $chunk->{chunk_index}) && ($_[1] > $chunk->{version})) { 1008 return $chunk->{name}; 1009 } 1010 } 1011 return undef; 1012} 1013######################################################### 1014package main; 1015 1016use strict; 1017use Getopt::Long; 1018use IO::File; 1019use File::Path; 1020use Cwd; 1021 1022sub usage { 1023 return <<END 1024level compiiler/decompiler 1025Usage: lcdc [-d input_file] [-o outdir] 1026 lcdc [-c input_dir] [-o outfile] 1027END 1028} 1029 1030my $input_file; 1031my $src_dir; 1032my $out; 1033 1034GetOptions( 1035 'd=s' => \$input_file, 1036 'c=s' => \$src_dir, 1037 'o=s' => \$out, 1038) or die usage(); 1039 1040my $work_dir = getcwd(); 1041 1042if (defined $input_file) { 1043 die "bad params\n" if (defined $src_dir); 1044 my $file = level->new(); 1045 print "reading level...\n"; 1046 $file->read($input_file); 1047 defined $out && do { 1048 File::Path::mkpath($out, 0); 1049 chdir $out or die "cannot change path to $out\n"; 1050 }; 1051 print "exporting level...\n"; 1052 $file->export(); 1053 print "done!\n"; 1054} else { 1055 die "bad params\n" if (defined $input_file); 1056 if (defined $src_dir) { 1057 chdir $src_dir or die "cannot change dir to $src_dir\n"; 1058 } 1059 my $file = level->new(); 1060 $out = 'level.new' unless defined $out; 1061 print "importing $src_dir...\n"; 1062 $file->import(); 1063 chdir $work_dir; 1064 print "writing $out...\n"; 1065 $file->write($out); 1066 print "done!\n"; 1067} 1068###########################################################