#!/usr/bin/perl -w # NAME: ac3dfile.pl # AIM: Read an parse an AC3D file # 02/11/2014 - Correction to the max/min gathering # 31/10/2014 - Add -D x,y,z to try to line up with world co-ordinatets # 22/07/2013 - add directory scan # 11/05/2013 - some UI improvements # 05/05/2013 geoff mclane http://geoffair.net/mperl use strict; use warnings; use File::Basename; # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] ) use File::Spec; # File::Spec->rel2abs($rel); use Cwd; my $os = $^O; my $perl_dir = '/home/geoff/bin'; my $PATH_SEP = '/'; my $temp_dir = '/tmp'; if ($os =~ /win/i) { $perl_dir = 'C:\GTools\perl'; $temp_dir = $perl_dir; $PATH_SEP = "\\"; } unshift(@INC, $perl_dir); require 'lib_utils.pl' or die "Unable to load 'lib_utils.pl' Check paths in \@INC...\n"; require 'lib_vec3.pm' or die "Unable to load 'lib_vec3.pm' Check paths in \@INC...\n"; # log file stuff our ($LF); my $pgmname = $0; if ($pgmname =~ /(\\|\/)/) { my @tmpsp = split(/(\\|\/)/,$pgmname); $pgmname = $tmpsp[-1]; } my $outfile = $temp_dir.$PATH_SEP."temp.$pgmname.txt"; open_log($outfile); # user variables my $VERS = "0.0.4 2014-10-31"; #my $VERS = "0.0.3 2013-07-21"; #my $VERS = "0.0.2 2013-05-11"; #my $VERS = "0.0.1 2013-03-17"; my $load_log = 0; my $in_file = ''; my $verbosity = 0; my $out_file = ''; my $show_dup_mats = 0; my @more_than_4 = (); my ($usr_len,$usr_wid,$usr_hgt); my $got_usr_dim = 0; # ### DEBUG ### my $debug_on = 0; #my $def_file = 'C:\FG\18\blendac3d\f16.ac'; my $def_file = 'C:\OSGeo4W\apache\htdocs\map-test2\ac\777-200.ac'; #8: ac_to_gl: Unrecognised token '<<<<<<< HEAD:Models/Weather/cirrus_alt1.ac' #my $def_file = 'C:\FG\fgdata\Models\Weather\cirrus_alt1.ac'; #ac_to_gl: Illegal vertex record. #my $def_file = 'C:\FG\fgdata\Aircraft\victor\Models\refuel-hose.ac'; #ac_to_gl: Mismatched double-quote ('"') in ' ' #3222: ac_to_gl: Unrecognised token '/systems/electrical/battery-bus/u-volts' #name " # /systems/electrical/battery-bus/u-volts # 10.0 # #Case" #my $def_file = 'C:\FG\fgdata\Aircraft\SenecaII\Models\AI\AI.ac'; #615: ac_to_gl: Unrecognised token 'SURF 0x10' #my $def_file = 'C:\FG\fgdata\Aircraft\PC-6\Models\porter.ac'; #83579: ac_to_gl: Unrecognised token 'texure "brushed1.png"' #my $def_file = 'C:\FG\fgdata\Aircraft\harrier\Models\harrier.ac'; #ac_to_gl: Illegal ref record. #my $def_file = 'C:\FG\fgdata\Aircraft\Dromader\Models\DropSystem.ac'; #14398: ac_to_gl: Unrecognised token 'light' #my $def_file = 'C:\FG\fgdata\Aircraft\dhc8\Models\dhc8.ac'; #17645: ac_to_gl: Unrecognised token '00522410077974' #my $def_file = 'C:\FG\fgdata\Aircraft\dc8-63\Models\Instruments\Yokes\yokes.ac'; #1271: ac_to_gl: Unrecognised token 'texoff -0.5 0.5' #my $def_file = 'C:\FG\fgdata\Aircraft\a4\Models\attitude-mod1.ac'; # 1300: ac_to_gl: Unrecognised token 'subdiv 1' #my $def_file = 'C:\FG\fgdata\Aircraft\A380\Models\FlightDeck\Glareshield\efis_c.ac'; #my $def_file = 'C:\FG\fgdata\AI\Aircraft\Dromader\Models\M18B_Dromader.ac'; #my $def_file = 'C:\FG\fgdata\AI\Aircraft\c310u3a\Models\c310u3a.ac'; # texoff record ??? #my $def_file = 'C:\FG\fgdata\AI\Aircraft\beech99\Models\beech99.ac'; #my $def_file = 'C:\FG\fgdata\Aircraft\c172p\Models\c172p.ac'; my $show_objs = 0; my $show_names = 0; my $show_verts = 0; my $show_surf = 0; my $show_refs = 0; my $show_mats = 0; my $show_OBJS = 0; my $show_NAMES = 0; my $show_VERTS = 0; my $show_SURF = 0; my $show_REFS = 0; my $show_MATS = 0; ### program variables my @warnings = (); my $cwd = cwd(); my %ac_objects = (); my $active_file = ''; my $curr_line = 0; my %avoid_dups = (); my %shown_filename = (); my %fix_me = (); my $done_surf_beyond = 0; my $did_not_split = 0; my $did_not_split3 = 0; my $bad_material_warn = 0; sub VERB1() { return $verbosity >= 1; } sub VERB2() { return $verbosity >= 2; } sub VERB5() { return $verbosity >= 5; } sub VERB9() { return $verbosity >= 9; } sub show_warnings($) { my ($val) = @_; if (@warnings) { prt( "\nGot ".scalar @warnings." WARNINGS...\n" ); foreach my $itm (@warnings) { prt("$itm\n"); } prt("\n"); } else { prt( "\nNo warnings issued.\n\n" ) if (VERB9()); } } sub pgm_exit($$) { my ($val,$msg) = @_; if (length($msg)) { $msg .= "\n" if (!($msg =~ /\n$/)); prt($msg); } show_warnings($val); close_log($outfile,$load_log); exit($val); } sub prtw($) { my ($tx) = shift; $tx =~ s/\n$//; prt("$tx\n"); push(@warnings,$tx); } sub vec3 { vec3->new(@_) } my $max_mat_len = 0; my @mat_index = (); my %materials = (); my %mats_used = (); my %mat_fields = ( 'rgb' => 1, 'amb' => 5, 'emis' => 9, 'spec' => 13, 'shi' => 17, 'trans' => 19 ); my @mat_order = qw( rgb amb emis spec shi trans ); sub show_materials() { my @arr = keys(%materials); my $cnt = scalar @arr; prt("Collected $cnt materials...\n"); my ($rh,$key,$ra,$k,$msg,$va); foreach $key (@mat_index) { ###foreach $key (@arr) { $msg = $key; $msg .= ' ' while (length($msg) < $max_mat_len); $rh = $materials{$key}; foreach $k (@mat_order) { ##### foreach $k (keys %{$rh}) { $va = ${$rh}{$k}; if (($k eq 'shi')||($k eq 'trans')) { $msg .= " $k ".${$va}[0]; } else { $msg .= " $k ".${$va}[0]." ".${$va}[1]." ".${$va}[2]; } } if (defined $mats_used{$key}) { $msg .= " Used ".$mats_used{$key}; } else { $msg .= " NOT USED"; } prt("$msg\n"); } } # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # MATERIAL %s rgb %f %f %f amb %f %f %f emis %f %f %f spec %f %f %f shi %d trans %f sub compare_material_hash($$$) { my ($mat,$rh1,$rh2) = @_; my @k1 = sort keys(%{$rh1}); my @k2 = sort keys(%{$rh2}); my $c1 = scalar @k1; my $c2 = scalar @k2; return 1 if ($c1 != $c2); my ($i,$key,$v1,$v2,$msg); for ($i = 0; $i < $c1; $i++) { return 1 if ($k1[$i] ne $k2[$i]); } $msg = ''; foreach $key (@k1) { $v1 = ${$rh1}{$key}; $v2 = ${$rh2}{$key}; if (${$v1}[0] != ${$v2}[0]) { $msg .= "item $key NOT same! ".${$v1}[0]." vs ".${$v2}[0]." "; #prt("Material $mat, item $key NOT same! ".${$v1}[0]." vs ".${$v2}[0]."\n"); #return 1; } } if (length($msg)) { prt("Material $mat: $msg\n"); return 1; } return 0; } sub prtw2($) { my $txt = shift; if (!defined $shown_filename{$active_file}) { $txt .= "File [$active_file]\n"; $shown_filename{$active_file} = 1; } prtw($txt); } sub get_material($) { my $line = shift; my @arr = space_split($line); my ($cnt,$key,$val,$rh,$tmp); $cnt = scalar @arr; my %h = (); if ($cnt > 20) { foreach $key (keys %mat_fields) { $val = $mat_fields{$key}; $tmp = $arr[$val]; if ($tmp eq $key) { # ok if (($key eq 'shi')||($key eq 'trans')) { $h{$key} = [$arr[$val+1],0,0]; } else { $h{$key} = [ $arr[$val+1], $arr[$val+2], $arr[$val+3] ]; } } else { if (!defined $avoid_dups{$tmp.$key}) { prtw2("WARNING: $curr_line:get_material: arr[$val] is $tmp, NOT $key?\n"); $avoid_dups{$tmp.$key} = 1; } return; } } $key = strip_quotes($arr[0]); if ($show_dup_mats && (defined $materials{$key})) { $rh = $materials{$key}; if (compare_material_hash($key,$rh,\%h)) { prtw("WARNING: MATERIAL $key is DUPLICATED with different values... Using 2nd\n"); $materials{$key} = \%h; # store this 'material' } } else { $materials{$key} = \%h; # store this 'material' $val = length($key); $max_mat_len = $val if ($val > $max_mat_len); push(@mat_index,$key); } } else { if ($bad_material_warn == 0) { prtw2("WARNING: $curr_line: BAD MATERIAL [$line]\n"); } $bad_material_warn++; } } sub get_mat_name($) { my $ind = shift; my $cnt = scalar @mat_index; my $mn = "INDEX $ind out of range $cnt"; if ($ind < $cnt) { $mn = $mat_index[$ind]; $mats_used{$mn}++; } return $mn; } sub is_decimal($) { my $num = shift; return 1 if ($num =~ /^[-+]?[0-9]*\.?[0-9]+$/); return 0; } sub process_in_file($) { my ($inf) = @_; $active_file = $inf; if (! open INF, "<$inf") { pgm_exit(1,"ERROR: Unable to open file [$inf]\n"); } my @lines = ; close INF; my ($iname,$idir,$iext) = fileparse($inf, qr/\.[^.]*/); my $lncnt = scalar @lines; prt("Processing $lncnt lines, from [$inf]...\n") if (VERB9()); my ($line,$i,$obj,$nam,$verts,$refs,$nserf,$serfn,$serfcnt); my ($stype,$shdg,$dec_nbr,$surf_type,$surf_shdg,$imat,$matnam); my ($j,@arr,$cnt,$ind,$ra,$len); my ($minx,$miny,$minz,$maxx,$maxy,$maxz,$x,$y,$z,$tcx,$tcy); my $max_refs = 0; my $min_refs = 99999999; my $refs_cnt = 0; my ($mxobj,$mxnam,$mxmatname,@mxvert,@mxrefs,$tmp,$mxlnn,$objlnn,$mxsurfcnt,$mxsurfnum,$mxsurflnn); my ($tex_name,$dir,$ff); my $mat_cnt = 0; my $obj_cnt = 0; my $vert_cnt = 0; my $min_verts = 99999999; my $max_verts = 0; my $lastsurflnn = 0; my $tex_count = 0; my %tex_files = (); my $used_count = 0; my $unused_count = 0; my $surf_count = 0; ($nam,$dir) = fileparse($inf); ut_fix_directory(\$dir); $curr_line = 0; $nserf = 0; $serfcnt = 0; my @vertexes = (); my @verts = (); if ($lncnt < 1) { prtw2("WARNING: Too few lines to be a AC3D file!\n"); return; } $line = $lines[0]; chomp $line; $line = trim_all($line); $len = length($line); if ($line =~ /^AC3D/) { $line = substr($line,4); prt("AC3D Version $line\n") if (VERB1()) } else { prtw2("WARNING: Not an AC3D file...\n"); return; } for ($i = 1; $i < $lncnt; $i++) { $line = $lines[$i]; chomp $line; $line = trim_all($line); $curr_line = $i + 1; $len = length($line); next if ($len == 0); # not really in the spec - a BLANK line, but here skip it if ($line =~ /^MATERIAL\s*/) { prt("$line\n") if (VERB9() || $show_mats); get_material(trim_all(substr($line,9))); #prt("$lnn: $line\n"); $mat_cnt++; } elsif ($line =~ /^OBJECT\s+/) { # OBJECT \%s $obj = strip_quotes(trim_all(substr($line,7))); prt("$curr_line: OBJECT $obj\n") if (VERB9() || $show_objs); @vertexes = (); # restart vertices for OBJECT @verts = (); $nam = ''; $matnam = ''; $obj_cnt++; $objlnn = $i + 1; } elsif ($line =~ /^name\s*/) { # *name \%s $nam = strip_quotes(trim_all(substr($line,5))); prt("name $nam\n") if (VERB9() || $show_names); # MAYBE can span several lines, but not per the spec } elsif ($line =~ /^data\s+/) { # *data \%d $i++; # skip next line } elsif ($line =~ /^texture\s+/) { # *texture \%s $tex_name = strip_quotes(trim_all(substr($line,8))); prt("texture \"$tex_name\"\n") if (VERB9() || $show_names); if (! defined $tex_files{$tex_name}) { $ff = $dir.$tex_name; if ($os =~ /win/i) { $ff = path_u2d($ff); } else { $ff = path_d2u($ff); } $tex_files{$tex_name} = $ff; if (! -f $ff) { prtw("WARNING: texture $tex_name NOT found in $dir\n"); $tex_files{$tex_name} .= " NF!"; } } $tex_count++; } elsif ($line =~ /^texrep\s+/) { # *texrep \%f \%f } elsif ($line =~ /^rot\s+/) { # *rot \%f \%f \%f \%f \%f \%f \%f \%f \%f } elsif ($line =~ /^loc\s+/) { # *loc \%f \%f \%f } elsif ($line =~ /^url\s+/) { # *url \%s } elsif ($line =~ /^numvert\s+/) { # *numvert \%d # lines of \%f \%f \%f $verts = trim_all(substr($line,8)); prt("List of $verts vertexes... obj $obj, name $nam\n") if (VERB5() || $show_verts); for ($j = 0; $j < $verts; $j++) { $curr_line = $i + $j + 1; $line = $lines[$curr_line]; chomp $line; $line = trim_all($line); @arr = split(/\s+/,$line); $cnt = scalar @arr; if ($cnt == 3) { $x = $arr[0]; $y = $arr[1]; $z = $arr[2]; prt("vertex $x $y $z\n") if (VERB9() || $show_VERTS); push(@vertexes, [$x,$y,$z,0]); push(@verts, vec3($x,$y,$z)); if ($vert_cnt == 0) { $minx = $x; $maxx = $x; $miny = $y; $maxy = $y; $minz = $z; $maxz = $z; # prt("start maxx $maxx minx $minx\n"); } else { # prt("x = $x "); if ($x < $minx) { $minx = $x; # prt("new min "); } if ($x > $maxx) { $maxx = $x; # prt("new max "); } # prt("\n"); $miny = $y if ($y < $miny); $maxy = $y if ($y > $maxy); $minz = $z if ($z < $minz); $maxz = $z if ($z < $maxx); } $vert_cnt++; } else { if ($did_not_split == 0) { prtw2("WARNING: $curr_line: Did not split to 3 vertexes!\nline [$line]\n"); } $did_not_split++; } } #### $vert_cnt += $verts; $min_verts = $verts if ($verts && ($verts < $min_verts)); $max_verts = $verts if ($verts > $max_verts); $i += $verts; # skip lines consumed } elsif ($line =~ /^numsurf\s+/) { if ($nserf) { prtw2("WARNING: $curr_line: Remain $nserf SURF beyond $serfcnt count!\n"); } # *numsurf \%d $nserf = trim_all(substr($line,8)); $serfcnt = $nserf; } elsif ($line =~ /^SURF\s+/) { # *SURF \%d $surf_count++; if ($nserf) { $nserf--; } else { if (!$done_surf_beyond) { prtw2("WARNING: $curr_line: A SURF beyond $serfcnt count!\n"); } $done_surf_beyond++; } $serfn = trim_all(substr($line,5)); $dec_nbr = hex($serfn); $stype = $dec_nbr & 0x0f; $shdg = $dec_nbr >> 4; if ($stype == 0) { $surf_type = 'polygon'; } elsif ($stype == 1) { $surf_type = 'closeline'; } elsif ($stype == 2) { $surf_type = 'line'; } else { $surf_type = 'UNKNOWN'; } if ($shdg == 0) { $surf_shdg = 'none'; } elsif ($shdg == 1) { $surf_shdg = 'shaded'; } elsif ($shdg == 1) { $surf_shdg = 'twosided'; } else { $surf_shdg = 'UNKNOWN'; } $lastsurflnn = $i + 1; prt("SURF $serfn $stype=$surf_type $shdg=$surf_shdg\n") if (VERB5() || $show_surf); } elsif ($line =~ /^mat\s+/) { # *mat \%d $imat = trim_all(substr($line,4)); $matnam = get_mat_name($imat); prt("mat $imat $matnam\n") if (VERB9()); } elsif ($line =~ /^refs\s+/) { # refs \%d # refs lines of \%d \%f \%f # Each line contains an index to the vertex and # the texture coordinates for this surface vertex. $refs = trim_all(substr($line,5)); prt("List of $refs reference for $matnam\n") if (VERB5() || $show_refs); my @reflist = (); for ($j = 0; $j < $refs; $j++) { $line = $lines[$i + $j + 1]; chomp $line; $line = trim_all($line); @arr = split(/\s+/,$line); $cnt = scalar @arr; if ($cnt == 3) { $ind = $arr[0]; $tcx = $arr[1]; $tcy = $arr[2]; push(@reflist,[$ind,$tcx,$tcy]); $cnt = scalar @vertexes; if ($ind < $cnt) { $ra = $vertexes[$ind]; ${$ra}[3]++; prt("index $ind coord $tcx $tcy on ".${$ra}[0]." ".${$ra}[1]." ".${$ra}[2]."\n") if (VERB9() || $show_REFS); } else { prtw2("WARNING: index $ind coord $tcx $tcy OUT OF RANGE! max $cnt\n"); } } else { if ($did_not_split3 == 0) { prtw2("WARNING: $curr_line: Did not split index + 2 coords!\nline [$line]\n"); } $did_not_split3++; } } if ($refs > $max_refs) { $max_refs = $refs; $mxlnn = $objlnn; $mxobj = $obj; $mxnam = $nam; $mxmatname = $matnam; $mxsurfcnt = $serfcnt; $mxsurfnum = $serfcnt - $nserf; $mxsurflnn = $lastsurflnn; @mxvert = @vertexes; @mxrefs = @reflist; } $min_refs = $refs if ($refs < $min_refs); $cnt = scalar @vertexes; my $uscnt = 0; my $uncnt = 0; for ($j = 0; $j < $cnt; $j++) { $ra = $vertexes[$ind]; if (${$ra}[3] == 0) { $uncnt++; } else { $uscnt++; } } prt("Of $cnt vertexes, found $uscnt used, $uncnt NOT referenced.\n") if (VERB9()); $used_count += $uscnt; $unused_count += $uncnt; $refs_cnt++; $i += $refs; } elsif ($line =~ /^kids\s+/) { # kids \%d } elsif ($line =~ /^crease\s+/) { } elsif ($line =~ /^subdiv\s+/) { } elsif ($line =~ /^texoff\s+/) { #} elsif ($line =~ /^Mesh\.(\d+)$/i) { #} elsif ($line =~ /^Plane\.(\d+)$/i) { #} elsif ($line =~ /^Plane/i) { } else { @arr = split(/\s+/,$line); $tmp = $arr[0]; if (! defined $fix_me{$tmp}) { prtw2("WARNING: $curr_line: WHAT IS THIS? [$line] FIX ME!\n"); $fix_me{$tmp} = 1; } } } my $sav_got_usr_dim = $got_usr_dim; ### get_dimensions($inf); prt("\nSummary of $inf\n"); if ($vert_cnt) { my ($ix,$iy,$iz); $x = $maxx - $minx; $y = $maxy - $miny; $z = $maxz - $minz; $ix = int(($maxx - $minx) + 0.5); $iy = int(($maxy - $miny) + 0.5); $iz = int(($maxz - $minz) + 0.5); prt("bbox: x,y,z $ix $iy $iz ($x,$y,$z) min $minx $miny $minz max $maxx $maxy $maxz\n"); if ($got_usr_dim) { prt("Dim $usr_len,$usr_wid,$usr_hgt ".($usr_len / $x).",".($usr_wid / $y).",".($usr_hgt /$z)."\n"); } } $got_usr_dim = $sav_got_usr_dim; prt(sprintf("%5d MATERIALS\n",$mat_cnt)); prt(sprintf("%5d OBJECTS ",$obj_cnt)); if ($vert_cnt) { $x = ($maxx + $minx) / 2; $y = ($maxy + $miny) / 2; $z = ($maxz - $minz) / 2; prt("Center xyz $x $y $z"); } prt("\n"); prt(sprintf("%5d vertices", $vert_cnt)." min $min_verts, max $max_verts, refs $used_count, unused $unused_count\n"); prt(sprintf("%5d refs", $refs_cnt)." min $min_refs, max $max_refs, SURF count $surf_count\n"); if ($max_refs > 4) { $tmp = scalar @mxvert; prt("$mxlnn: OBJECT $mxobj, name $mxnam, mat $mxmatname, with $tmp verts, $mxsurflnn: surf $mxsurfnum of $mxsurfcnt, 1st max refs $max_refs.\n"); ###prt("First with $max_refs - OBJECT $mxobj, name $mxnam, mat $mxmatname, with $tmp verts.\n"); push(@more_than_4,$inf); } if ($tex_count) { @arr = sort keys %tex_files; if (VERB1()) { prt(sprintf("%5d textures",$tex_count)."\n"); foreach $tmp (@arr) { $ff = $tex_files{$tmp}; prt("$ff\n"); } } else { prt(sprintf("%5d textures",$tex_count).", ".join(" ",@arr)."\n"); } } } sub process_in_directory($); sub process_in_directory($) { my $dir = shift; if (!opendir(DIR,$dir)) { prt("WARNING: Open directory [$dir] FAILED\n"); return; } my @files = readdir(DIR); closedir(DIR); ut_fix_directory(\$dir); my ($file,$ff); my @dirs = (); my @acfiles = (); foreach $file (@files) { next if ($file eq '.'); next if ($file eq '..'); $ff = $dir.$file; if (-d $ff) { push(@dirs,$ff); } elsif (-f $ff) { if ($file =~ /\.ac$/i) { push(@acfiles,$ff); } } } foreach $file (@acfiles) { process_in_file($file); } foreach $dir (@dirs) { process_in_directory($dir); } } ######################################### ### MAIN ### parse_args(@ARGV); if (-d $in_file) { process_in_directory($in_file); } else { process_in_file($in_file); } if (@more_than_4) { prt("The following file(s) have refs with more than 4 entries\n"); prt(join("\n",@more_than_4)."\n"); } #show_materials() if (VERB5()); pgm_exit(0,""); ######################################## sub need_arg { my ($arg,@av) = @_; pgm_exit(1,"ERROR: [$arg] must have a following argument!\n") if (!@av); } sub get_dimensions($) { my $inf = shift; if (open INF, "<$inf") { my @lines = ; close INF; my ($line,$x,$y,$z,$len); my $msg = ''; foreach $line (@lines) { chomp $line; $line = trim_all($line); $len = length($line); next if ($len == 0); $line =~ s/\s+m$//; $line = trim_all($line); if ($line =~ /^Length:\s/i) { $x = trim_all(substr($line,8)); $msg .= "got Length: $x "; } elsif ($line =~ /^Wingspan:\s/i) { $y = trim_all(substr($line,9)); $msg .= "got Wingspan: $y "; } elsif ($line =~ /^Height:\s/i) { $z = trim_all(substr($line,7)); $msg .= "got Height: $z "; } } if ($x && $y && $z && is_decimal($x) && is_decimal($y) && is_decimal($z)) { $usr_len = $x; $usr_wid = $y; $usr_hgt = $z; $got_usr_dim = 1; } else { prt("Expected file with Length: Wingspan: and Height: dimensions,\n"); prt("on separate lines, followed by a double being the size in meters.\n"); prt("The line may end in 'm' which is ignored.\n"); prt("$msg\n") if (length($msg)); pgm_exit(1,"Error: Failed to get dimension from [$inf]\n"); } } else { pgm_exit(1,"Error: Failed to 'open' dimensions file [$inf]\n"); } } sub parse_args { my (@av) = @_; my ($arg,$sarg,$tmp,@arr); while (@av) { $arg = $av[0]; if ($arg =~ /^-/) { $sarg = substr($arg,1); $sarg = substr($sarg,1) while ($sarg =~ /^-/); if (($sarg =~ /^h/i)||($sarg eq '?')) { give_help(); pgm_exit(0,"Help exit(0)"); } elsif ($sarg =~ /^m/) { $show_dup_mats = 1; prt("Set to show duplicate materials\n") if (VERB1()); } elsif ($sarg =~ /^d/) { need_arg(@av); shift @av; $sarg = $av[0]; get_dimensions($sarg); prt("Got Length: $usr_len Wingspan: $usr_wid Height: $usr_hgt\n") if (VERB1()); } elsif ($sarg =~ /^D/) { need_arg(@av); shift @av; $sarg = $av[0]; @arr = split(",",$sarg); $tmp = scalar @arr; if ($tmp != 3) { pgm_exit(1,"Error: Dimension did not split in 3 on comma! Got $tmp.\n"); } $usr_len = $arr[0]; $usr_wid = $arr[1]; $usr_hgt = $arr[2]; $got_usr_dim = 1; prt("Got Length: $usr_len Wingspan: $usr_wid Height: $usr_hgt\n") if (VERB1()); } elsif ($sarg =~ /^v/) { if ($sarg =~ /^v.*(\d+)$/) { $verbosity = $1; } else { while ($sarg =~ /^v/) { $verbosity++; $sarg = substr($sarg,1); } } prt("Verbosity = $verbosity\n") if (VERB1()); } elsif ($sarg =~ /^l/) { if ($sarg =~ /^ll/) { $load_log = 2; } else { $load_log = 1; } prt("Set to load log at end. ($load_log)\n") if (VERB1()); #} elsif ($sarg =~ /^o/) { # need_arg(@av); # shift @av; # $sarg = $av[0]; # $out_file = $sarg; # prt("Set out file to [$out_file].\n") if (VERB1()); } elsif ($sarg =~ /^s/) { need_arg(@av); shift @av; $sarg = $av[0]; if ($sarg =~ /^a/i) { $show_objs = 1; $show_names = 1; $show_verts = 1; $show_surf = 1; $show_refs = 1; $show_mats = 1; $tmp = 'all'; if ($sarg =~ /^A/) { $show_OBJS = 1; $show_NAMES = 1; $show_VERTS = 1; $show_SURF = 1; $show_REFS = 1; $show_MATS = 1; $tmp = 'ALL'; } prt("Set to show $tmp.\n") if (VERB1()); } elsif ($sarg =~ /^o/i) { $show_objs = 1; $tmp = 'objects'; if ($sarg =~ /^O/) { $tmp = 'OBJECTS'; $show_OBJS = 1; } prt("Set to show $tmp.\n") if (VERB1()); } elsif ($sarg =~ /^r/i) { $show_refs = 1; $tmp = 'refs'; if ($sarg =~ /^R/) { $tmp = 'REFS'; $show_REFS = 1; } prt("Set to show $tmp.\n") if (VERB1()); } elsif ($sarg =~ /^s/i) { $show_surf = 1; $tmp = 'surf'; if ($sarg =~ /^S/) { $tmp = 'SURF'; $show_SURF = 1; } prt("Set to show $tmp.\n") if (VERB1()); } elsif ($sarg =~ /^v/i) { $show_verts = 1; $tmp = 'verts'; if ($sarg =~ /^V/) { $tmp = 'VERTS'; $show_VERTS = 1; } prt("Set to show $tmp.\n") if (VERB1()); } elsif ($sarg =~ /^m/i) { $show_mats = 1; $tmp = 'mats'; if ($sarg =~ /^M/) { $tmp = 'MATS'; $show_MATS = 1; } prt("Set to show $tmp.\n") if (VERB1()); } elsif ($sarg =~ /^n/i) { $show_names = 1; $tmp = 'names'; if ($sarg =~ /^N/) { $tmp = 'NAMES'; $show_NAMES = 1; } prt("Set to show NAMES.\n") if (VERB1()); } else { prt("Must be"); out_type_list(); pgm_exit(1,"Invalid show [$sarg]\n"); } } else { pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n"); } } else { $in_file = File::Spec->rel2abs($arg); ###$in_file = $arg; if (-f $in_file) { prt("Set input file to [$in_file]\n") if (VERB1()); } elsif (-d $in_file) { prt("Set input directory to [$in_file]\n") if (VERB1()); } else { pgm_exit(1,"Item [$in_file] is not a file or directory!\n"); } } shift @av; } if ($debug_on) { prtw("WARNING: DEBUG is ON!\n"); if (length($in_file) == 0) { $in_file = $def_file; prt("Set DEFAULT input to [$in_file]\n"); } #$load_log = 1; #$show_objs = 1; #$show_verts = 1; #$show_surf = 1; #$show_refs = 1; } if (length($in_file) == 0) { pgm_exit(1,"ERROR: No input files found in command!\n"); } #if (-f $in_file) { # pgm_exit(1,"ERROR: Unable to find in file [$in_file]! Check name, location...\n"); #} } sub out_type_list() { prt(" types are 'mats', 'obj', 'names', 'vert', 'surf', 'refs' and 'all'. More if in CAPS\n"); } sub give_help { prt("$pgmname: version $VERS\n"); prt("Usage: $pgmname [options] in-file\n"); prt("Options:\n"); prt(" --help (-h or -?) = This help, and exit 0.\n"); prt(" --verb[n] (-v) = Bump [or set] verbosity. (def=$verbosity)\n"); prt(" --mat (-m) = Show duplicate materials. (def=$show_dup_mats)\n"); prt(" --load (-l) = Load LOG at end. (def=$outfile)\n"); prt(" --Dim x,y,z (-D) = Aircraft dimension in meters (len,spa,hgt)\n"); prt(" --dim (-d) = Load dimensions from a file.\n"); prt(" --show (-s) = Show this type of objects. (def=none)\n"); out_type_list(); ###prt(" --out (-o) = Write output to this file.\n"); } sub get_ref() { my $txt = <> 4) specify the shading and backface. bit1 = shaded surface bit2 = twosided. *mat \%d The index to the material that this surface has. refs \%d refs lines of \%d \%f \%f The number of vertices in the surface. This number indicates the number of lines following. Each line contains an index to the vertex and the texture coordinates for this surface vertex. kids \%d This is the final token of an object section and it must exist. If the parameter is a number > 0 then more objects are recursively loaded as children of the current object. Here is an example file - a simple rectangle (white) AC3Db MATERIAL "" rgb 1 1 1 amb 0.2 0.2 0.2 emis 0 0 0 spec 0.5 0.5 0.5 shi 10 trans 0 OBJECT world kids 1 OBJECT poly name "rect" loc 1 0.5 0 numvert 4 -1 0.5 0 1 0.5 0 1 -0.5 0 -1 -0.5 0 numsurf 1 SURF 0x20 mat 0 refs 4 3 0 0 2 1 0 1 1 1 0 0 1 kids 0 Another example - an object with 7 vertices (no surfaces, no materials defined) This is a good way of getting point data into AC3D. The Vertex->create convex-surface/object can be used on these vertices to 'wrap' a 3d shape around them AC3Db OBJECT poly numvert 7 -0.83 -0.235 -0.04 -0.63 0.185 -0.04 -0.55 0.235 -0.25 -0.33 0.235 0.29 0.09 0.235 -0.29 0.33 -0.195 -0.04 0.83 0.005 -0.04 kids 0 If you write a loader then you least you need is code to handle the object token, and the objects numvert/vertice and numsurf/sufaces - esentially the geometry of the model. You can ignore any line that starts with a token other than these e,g textures, rotation, location etc. Last revision 27/03/03 ac - removed old email address EOF return $txt; } sub get_osg_txt() { my $txt = <> num; // list of materials required- generate one geode per material for (unsigned n = 0; n < num; ++n) { stream >> token; if (token != "SURF") OSG_FATAL << "osgDB ac3d reader: expected SURF line while reading object stream >> token; if (token != "mat") OSG_FATAL << "osgDB ac3d reader: expected mat line while reading object stream >> matIdx; // read the refs stream >> token; if (token != "refs") OSG_FATAL << "osgDB ac3d reader: expected refs line while reading object stream >> nRefs; for (unsigned i = 0; i < nRefs; ++i) { // Read the vertex index stream >> index; if (vertexSet->size() <= index) OSG_FATAL << "osgDB ac3d reader: invalid ref vertex index while reading object // Read the texture corrdinates stream >> texCoord[0] >> texCoord[1]; } } else if (token == "kids") { stream >> num; for (unsigned n = 0; n < num; n++) { osg::Node *k = readObject(stream, fileData, transform*parentTransform, textureData); if (k == 0) OSG_FATAL << "osgDB ac3d reader: error reading child object" << std::endl; } EOF return $txt; } # eof - ac3dfile.pl