#!/usr/bin/perl -w # NAME: chkjsac.pl # AIM: Read a the javsscipt file generated from an AC3D file, and... # 10/05/2013 - Begin to use the JSON parser # 07/05/2013 geoff mclane http://geoffair.net/mperl use strict; use warnings; use File::Basename; # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] ) use JSON; use Data::Dumper; 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"; # 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.1 2013-03-17"; my $load_log = 0; my $in_file = ''; my $verbosity = 0; my $out_file = ''; my @in_files = (); # ### DEBUG ### my $debug_on = 1; #Verts 2692 8076, Norms 2692 8076, Faces 4001 32038 #x,y,z MINS -8.41521,-1.91735,-4.79505 MAXS 9.07555,3.24977,4.8164 my $def_file = 'C:\FG\18\blendac3d\f16-4.js'; #Verts 1393 4179, Norms 1246 3738, Faces 2149 17192 #x,y,z MINS -5.38967,-0.0999272,-1.87188 MAXS 0.445233,1.70093,1.81699 #my $def_file = 'C:\FG\18\blendac3d\f16.js'; #my $def_file = 'C:\FG\18\blendac3d\cube.js'; #my $def_file2 = 'C:\FG\18\blendac3d\cube2.js'; #my $def_file = 'C:\FG\17\fgx-globe\fgx-planes\f16\f16.js'; #my $def_file2 = 'C:\FG\18\blendac3d\f16.js'; ###my $def_file3 = 'C:\FG\18\ac3d2gl\build\ac3dloader\tempdump.json'; #my $def_file3 = 'C:\OSGeo4W\apache\htdocs\fgx-globe\cookbook\load-plane-3d\test\test.js'; ### program variables my @warnings = (); my $cwd = cwd(); 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 isBitSet($$) { my ($val, $pos) = @_; return ($val & ( 1 << $pos )) ? 1 : 0; } sub show_type_flag($) { my $type = shift; my $isQuad = isBitSet( $type, 0 ); my $hasMaterial = isBitSet( $type, 1 ); my $hasFaceUv = isBitSet( $type, 2 ); my $hasFaceVertexUv = isBitSet( $type, 3 ); my $hasFaceNormal = isBitSet( $type, 4 ); my $hasFaceVertexNormal = isBitSet( $type, 5 ); my $hasFaceColor = isBitSet( $type, 6 ); my $hasFaceVertexColor = isBitSet( $type, 7 ); prt("Type $type bits ".$isQuad.$hasMaterial.$hasFaceUv.$hasFaceVertexUv.$hasFaceNormal.$hasFaceVertexNormal.$hasFaceColor.$hasFaceVertexColor." "); prt(sprintf("isQad=%s ", ($isQuad ? "On" : "Off"))); prt(sprintf("hasMat=%s ", ($hasMaterial ? "On" : "Off"))); prt(sprintf("hasFUv=%s ", ($hasFaceUv ? "On" : "Off"))); prt(sprintf("hasVUv=%s ", ($hasFaceVertexUv ? "On" : "Off"))); prt(sprintf("hasFNorm=%s ", ($hasFaceNormal ? "On" : "Off"))); prt(sprintf("hasVNorm=%s ", ($hasFaceVertexNormal ? "On" : "Off"))); prt(sprintf("hasFC=%s ", ($hasFaceColor ? "On" : "Off"))); prt(sprintf("hasVC=%s ", ($hasFaceVertexColor ? "On" : "Off"))); prt("\n"); } sub check_faces($$$) { my ($ra,$faces,$norms) = @_; # ( \@farr, $faces ); my $cnt = scalar @{$ra}; my $offset = 0; my ($type,$isQuad,$hasMaterial,$hasFaceUv,$hasFaceVertexUv); my ($hasFaceNormal,$hasFaceVertexNormal,$hasFaceColor,$hasFaceVertexColor); my ($nVertices,@face,$i); my $nUvLayers = 0; my $nNormals = scalar @{$norms}; while ($offset < $cnt) { $type = ${$ra}[$offset++]; show_type_flag($type); $isQuad = isBitSet( $type, 0 ); $hasMaterial = isBitSet( $type, 1 ); $hasFaceUv = isBitSet( $type, 2 ); $hasFaceVertexUv = isBitSet( $type, 3 ); $hasFaceNormal = isBitSet( $type, 4 ); $hasFaceVertexNormal = isBitSet( $type, 5 ); $hasFaceColor = isBitSet( $type, 6 ); $hasFaceVertexColor = isBitSet( $type, 7 ); #//console.log("type", type, "bits", isQuad, hasMaterial, hasFaceUv, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor); prt("Type $type bits ".$isQuad.$hasMaterial.$hasFaceUv.$hasFaceVertexUv.$hasFaceNormal.$hasFaceVertexNormal.$hasFaceColor.$hasFaceVertexColor." "); @face = (); if ( $isQuad ) { #face = new THREE.Face4(); $face[0] = ${$ra}[ $offset ++ ]; $face[1] = ${$ra}[ $offset ++ ]; $face[2] = ${$ra}[ $offset ++ ]; $face[3] = ${$ra}[ $offset ++ ]; $nVertices = 4; } else { #face = new THREE.Face3(); $face[0] = ${$ra}[ $offset ++ ]; $face[1] = ${$ra}[ $offset ++ ]; $face[2] = ${$ra}[ $offset ++ ]; $nVertices = 3; } prt(join(",",@face)." "); if ( $hasMaterial ) { my $materialIndex = ${$ra}[ $offset ++ ]; # face.materialIndex = materialIndex; } # // to get face <=> uv index correspondence # fi = geometry.faces.length; if ( $hasFaceUv ) { if ($nUvLayers) { for ( $i = 0; $i < $nUvLayers; $i++ ) { #uvLayer = json.uvs[ i ]; my $uvIndex = ${$ra}[ $offset ++ ]; #u = uvLayer[ uvIndex * 2 ]; #v = uvLayer[ uvIndex * 2 + 1 ]; #geometry.faceUvs[ i ][ fi ] = new THREE.Vector2( u, v ); } } else { prt("FACES failed - has FaceUv flag, but NO uvLayers!\n"); last; } } if ( $hasFaceVertexUv ) { if ($nUvLayers) { for ( $i = 0; $i < $nUvLayers; $i++ ) { #uvLayer = json.uvs[ i ]; #uvs = []; #for ( j = 0; j < nVertices; j ++ ) { my $uvIndex = ${$ra}[ $offset ++ ]; # u = uvLayer[ uvIndex * 2 ]; # v = uvLayer[ uvIndex * 2 + 1 ]; # uvs[ j ] = new THREE.Vector2( u, v ); #} #geometry.faceVertexUvs[ i ][ fi ] = uvs; } } else { prt("FACES failed - has FaceVertexUv flag, but NO uvLayers!\n"); last; } } if ( $hasFaceNormal ) { my $normalIndex = ${$ra}[ $offset ++ ] * 3; #normal = new THREE.Vector3(); #normal.x = normals[ normalIndex ++ ]; #normal.y = normals[ normalIndex ++ ]; #normal.z = normals[ normalIndex ]; #face.normal = normal; prt("FaceNorm index $normalIndex "); } if ( $hasFaceVertexNormal ) { prt("FaceVertNorm "); if ($nNormals) { for ( $i = 0; $i < $nVertices; $i++ ) { my $normalIndex = ${$ra}[ $offset ++ ] * 3; #normal = new THREE.Vector3(); #normal.x = normals[ normalIndex ++ ]; #normal.y = normals[ normalIndex ++ ]; #normal.z = normals[ normalIndex ]; #face.vertexNormals.push( normal ); prt( ${$norms}[ $normalIndex++ ]." " ); prt( ${$norms}[ $normalIndex++ ]." " ); prt( ${$norms}[ $normalIndex++ ]." " ); } } else { prt("FACES failed - has FaceVertexNorm flag, but NO nNorms!\n"); last; } } if ( $hasFaceColor ) { prt("hasFaceColor "); my $colorIndex = ${$ra}[ $offset ++ ]; ###color = new THREE.Color( colors[ colorIndex ] ); ###face.color = color; } if ( $hasFaceVertexColor ) { prt("hasFaceVertColor "); for ( $i = 0; $i < $nVertices; $i++ ) { my $colorIndex = ${$ra}[ $offset ++ ]; #color = new THREE.Color( colors[ colorIndex ] ); #face.vertexColors.push( color ); } } prt("\n"); ###last; } } my %threejs_master = ( 'morphTargets' => 'ARRAY', 'faces' => 'ARRAY', 'bones' => 'ARRAY', 'colors' => 'ARRAY', 'vertices' => 'ARRAY', 'normals' => 'ARRAY', 'uvs' => 'ARRAY', 'materials' => 'ARRAY', 'skinWeights' => 'ARRAY', 'skinIndices' => 'ARRAY', 'scale' => 'TEXT', 'metadata' => 'HASH', 'animation' => 'HASH' ); my %threejs_meta = ( 'morphTargets' => 'TEXT', 'faces' => 'TEXT', 'bones' => 'TEXT', 'colors' => 'TEXT', 'formatVersion' => 'TEXT', 'vertices' => 'TEXT', 'normals' => 'TEXT', 'uvs' => 'ARRAY', 'materials' => 'TEXT', 'generatedBy' => 'TEXT' ); sub show_json_threejs($$) { my ($rh,$fil) = @_; my $rt = ref($rh); if ($rt ne 'HASH') { prt("Not a HASH! got [$rt]\n"); return; } my ($item,$val,$cnt,$rtj,$key,$v2,$typ,$cnt); #prt(Dumper($rh)); my $nmFaces = 0; my $nmVerts = 0; my $nmNorms = 0; $rtj = \%threejs_meta; $item = 'metadata'; if (defined ${$rh}{$item}) { $val = ${$rh}{$item}; $rt = ref($val); prt("Display of the $item...\n"); if ($rt eq 'HASH') { foreach $key (keys %{$rtj}) { $typ = ${$rtj}{$key}; if (defined ${$val}{$key}) { $v2 = ${$val}{$key}; if ($typ eq 'TEXT') { prt("$key=$v2 "); if ($key eq 'faces') { $nmFaces = $v2; } elsif ($key eq 'normals') { $nmNorms = $v2; } elsif ($key eq 'vertices') { $nmVerts = $v2; } } } else { prt("$key: not in $item!\n"); } } prt("\n"); } else { prt("$item not a HASH! got [$rt]\n"); } } else { prt("$item not found in HASH!\n"); } #'faces' => 'ARRAY', #'vertices' => 'ARRAY', #'normals' => 'ARRAY', prt("Dealing with other than metadata...\n"); my $nFaces = 0; my $nVerts = 0; my $nNorms = 0; my ($faces,$verts,$norms); $rtj = \%threejs_master; foreach $item (keys %{$rtj}) { next if ($item eq 'metadata'); if (defined ${$rh}{$item}) { $val = ${$rh}{$item}; $rt = ref($val); if ($rt eq 'ARRAY') { $cnt = scalar @{$val}; prt("ARRAY $item $cnt "); if ($item eq 'faces') { $nFaces = $cnt; $faces = $val; } elsif ($item eq 'normals') { $nNorms = $cnt; $norms = $val; } elsif ($item eq 'vertices') { $verts = $val; $nVerts = $cnt } } elsif ($rt eq 'HASH') { $cnt = scalar keys(%{$val}); prt("HASH $item $cnt "); } elsif ($rt eq '') { prt("TEXT: $item = $val\n"); } else { prt("$item not an ARRAY/HASH/TEXT! got [$rt]\n"); } } else { prt("$item not found in HASH!\n"); } } prt("\n"); prt("Verts $nmVerts $nVerts, Norms $nmNorms $nNorms, Faces $nmFaces $nFaces\n"); my $off = 0; my ($x,$y,$z); my ($minx,$miny,$minz,$maxx,$maxy,$maxz); if ($nVerts && $nmVerts) { $off = 0; $minx = ${$verts}[$off++]; $miny = ${$verts}[$off++]; $minz = ${$verts}[$off++]; $off = 0; $maxx = ${$verts}[$off++]; $maxy = ${$verts}[$off++]; $maxz = ${$verts}[$off++]; while ($off < $nVerts) { $x = ${$verts}[$off++]; $y = ${$verts}[$off++]; $z = ${$verts}[$off++]; prt("$x,$y,$z ") if (VERB9()); $minx = $x if ($x < $minx); $miny = $y if ($y < $miny); $minz = $z if ($z < $minz); $maxx = $x if ($x > $maxx); $maxy = $y if ($y > $maxy); $maxz = $z if ($z > $maxz); } prt("\n") if (VERB9()); } prt("x,y,z MINS $minx,$miny,$minz MAXS $maxx,$maxy,$maxz\n"); } sub process_in_file($) { my ($inf) = @_; if (! open INF, "<$inf") { pgm_exit(1,"ERROR: Unable to open file [$inf]\n"); } my @lines = ; close INF; my $lncnt = scalar @lines; my ($line,$cnt,$lnn,$i,$fid,$secs,$ctr,$tm,$ccnt); $cnt = sprintf("%3d",$lncnt); prt("\nProcessing $cnt lines, from [$inf]...\n"); $line = join(" ",@lines); my $json = JSON->new->allow_nonref; my $perl_scalar = $json->decode( $line ); show_json_threejs($perl_scalar,$inf); } # "vertices" : 1393, # "faces" : 2149, # "normals" : 1246, sub process_in_file_DIRECT($) { my ($inf) = @_; if (! open INF, "<$inf") { pgm_exit(1,"ERROR: Unable to open file [$inf]\n"); } my @lines = ; close INF; my $lncnt = scalar @lines; prt("\nProcessing $lncnt lines, from [$inf]...\n"); my ($line,$i,$lnn,$cnt); my $verts = 0; my $faces = 0; my $norms = 0; my $vlist = ''; my $flist = ''; my $nlist = ''; my @varr = (); my @farr = (); my @narr = (); my $minx = 99999; my $maxx = -99999; my $miny = 99999; my $maxy = -99999; my $minz = 99999; my $maxz = -99999; my ($vcnt,$vx,$vy,$vz); $lnn = 0; my $fvc = 0; my $fnc = 0; my $ffc = 0; my $fvl = 0; my $fnl = 0; my $ffl = 0; foreach $line (@lines) { chomp $line; $lnn++; if ($line =~ /^\s*"vertices"\s*:\s*(\d+),/) { $verts = $1; prt("$lnn: vertices = $verts\n"); $fvc = 1; } elsif ($line =~ /^\s*"faces"\s*:\s*(\d+),/) { $faces = $1; prt("$lnn: faces = $faces\n"); $ffc = 1; } elsif ($line =~ /^\s*"normals"\s*:\s*(\d+),/) { $norms = $1; prt("$lnn: normals = $norms\n"); $fnc = 1; } elsif ($line =~ /^\s*"vertices"\s*:\s*\[(.+)\]\s*,/) { $vlist = $1; @varr = split(',',$vlist); $cnt = scalar @varr; prt("$lnn: vertices = "); if (length($vlist) > 80) { prt(substr($vlist,0,80)."...\n"); } else { prt("$vlist\n"); } $vcnt = ($cnt / 3); if ($vcnt == $verts) { prt("VERTS: Total count $cnt, ie $vcnt sets of 3 verts ($verts)\n"); } else { prtw("WARNING: VERTS total count $cnt, ie $vcnt sets of 3 verts ($verts)\nFile: $inf\n"); } $fvl = 1; } elsif ($line =~ /^\s*"faces"\s*:\s*\[(.+)\]\s*,/) { $flist = $1; @farr = split(',',$flist); $cnt = scalar @farr; prt("$lnn: faces = "); if (length($flist) > 80) { prt(substr($flist,0,80)."...\n"); } else { prt("$flist\n"); } prt("FACES: Total count $cnt ($faces)\n"); check_faces( \@farr, $faces, \@narr ); $vcnt = ($cnt / 8); # if ($vcnt == $faces) { # prt("FACES: Total count $cnt, ie $vcnt sets of 8 values ($faces)\n"); # } else { # $vcnt = ($cnt / 3); # if ($vcnt == $faces) { # prt("FACES: Total count $cnt, ie $vcnt sets of 3 values ($faces)\n"); # } else { # prtw("WARNING: FACES total count $cnt, ie $vcnt sets of 3 values ($faces)\nFile: $inf\n"); # } # } $ffl = 1; } elsif ($line =~ /^\s*"normals"\s*:\s*\[(.+)\]\s*,/) { $nlist = $1; @narr = split(',',$nlist); $cnt = scalar @narr; prt("$lnn: normals = "); if (length($nlist) > 80) { prt(substr($nlist,0,80)."...\n"); } else { prt("$nlist\n"); } $vcnt = ($cnt / 3); if ($vcnt == $norms) { prt("NORMS: Total count $cnt ie $vcnt sets of 3 ($norms)\n"); } else { prt("WARNING: NORMS total count $cnt ie $vcnt sets of 3 ($norms)\nFile: $inf\n"); } $fnl = 1; } } if ($fvc && $fnc && $ffc && $fvl && $fnl && $ffl) { prt("Appears ALL items FOUND...\n") if (VERB9()); } else { prtw("WARNING: Something NOT found $fvc $fnc $ffc $fvl $fnl $ffl!\n"); } $cnt = scalar @varr; $vcnt = int($cnt / 3); if (($cnt >= 3) && $vcnt) { $minx = $varr[0]; $maxx = $varr[0]; $miny = $varr[1]; $maxy = $varr[1]; $minz = $varr[2]; $maxz = $varr[2]; for ($i = 0; $i < $vcnt; $i++) { $vx = $varr[($i * 3) + 0]; $vy = $varr[($i * 3) + 1]; $vz = $varr[($i * 3) + 2]; $minx = $vx if ($vx < $minx); $maxx = $vx if ($vx > $maxx); $miny = $vy if ($vy < $miny); $maxy = $vy if ($vy > $maxy); $minz = $vz if ($vz < $minz); $maxz = $vz if ($vz > $maxz); } prt("x,y,z MINS: $minx,$miny,$minz MAXS: $maxx,$maxy,$maxz\n"); } else { prtw("WARNING: Got count $cnt, vert count $vcnt! WHAT IS WRONG?\n"); } } sub process_in_files($) { my $ra = shift; my ($file); my %dupes = (); foreach $file (@{$ra}) { if (!defined $dupes{$file}) { $dupes{$file} = 1; process_in_file($file); } } } ######################################### ### MAIN ### parse_args(@ARGV); process_in_files(\@in_files); pgm_exit(0,""); ######################################## sub need_arg { my ($arg,@av) = @_; pgm_exit(1,"ERROR: [$arg] must have a following argument!\n") if (!@av); } sub parse_args { my (@av) = @_; my ($arg,$sarg); 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 =~ /^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()); } else { pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n"); } } else { $in_file = $arg; push(@in_files,$in_file); prt("Set input to [$in_file]\n") if (VERB1()); } shift @av; } if ($debug_on) { prtw("WARNING: DEBUG is ON!\n"); if (length($in_file) == 0) { $in_file = $def_file; push(@in_files,$in_file); prt("Set DEFAULT input to [$in_file]\n"); #push(@in_files,$def_file2); #push(@in_files,$def_file3); } #$load_log = 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 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(" --load (-l) = Load LOG at end. ($outfile)\n"); prt(" --out (-o) = Write output to this file.\n"); } sub get_threejs_json_parse() { my $txt = < uv index correspondence fi = geometry.faces.length; if ( hasFaceUv ) { for ( i = 0; i < nUvLayers; i++ ) { uvLayer = json.uvs[ i ]; uvIndex = faces[ offset ++ ]; u = uvLayer[ uvIndex * 2 ]; v = uvLayer[ uvIndex * 2 + 1 ]; geometry.faceUvs[ i ][ fi ] = new THREE.Vector2( u, v ); } } if ( hasFaceVertexUv ) { for ( i = 0; i < nUvLayers; i++ ) { uvLayer = json.uvs[ i ]; uvs = []; for ( j = 0; j < nVertices; j ++ ) { uvIndex = faces[ offset ++ ]; u = uvLayer[ uvIndex * 2 ]; v = uvLayer[ uvIndex * 2 + 1 ]; uvs[ j ] = new THREE.Vector2( u, v ); } geometry.faceVertexUvs[ i ][ fi ] = uvs; } } if ( hasFaceNormal ) { normalIndex = faces[ offset ++ ] * 3; normal = new THREE.Vector3(); normal.x = normals[ normalIndex ++ ]; normal.y = normals[ normalIndex ++ ]; normal.z = normals[ normalIndex ]; face.normal = normal; } if ( hasFaceVertexNormal ) { for ( i = 0; i < nVertices; i++ ) { normalIndex = faces[ offset ++ ] * 3; normal = new THREE.Vector3(); normal.x = normals[ normalIndex ++ ]; normal.y = normals[ normalIndex ++ ]; normal.z = normals[ normalIndex ]; face.vertexNormals.push( normal ); } } if ( hasFaceColor ) { colorIndex = faces[ offset ++ ]; color = new THREE.Color( colors[ colorIndex ] ); face.color = color; } if ( hasFaceVertexColor ) { for ( i = 0; i < nVertices; i++ ) { colorIndex = faces[ offset ++ ]; color = new THREE.Color( colors[ colorIndex ] ); face.vertexColors.push( color ); } } geometry.faces.push( face ); } }; EOF return $txt; } # eof - template.pl