home *** CD-ROM | disk | FTP | other *** search
/ Xentax forum attachments archive / xentax.7z / 5213 / emo2smd_converter.7z / emo2smd_converter.pl
Encoding:
Text File  |  2009-08-03  |  10.5 KB  |  354 lines

  1. #
  2. # Street Fighter 4 EMO2SMD Converter
  3. # by magnum29
  4. #
  5.  
  6. use Math::Trig;
  7.  
  8. print "Enter an EMO file:\n";
  9. chomp( my $emo = <STDIN> );
  10. $emo =~ s/^"//;
  11. $emo =~ s/"$//;
  12. open $INPUT, "<$emo" or die "Couldn't open $emo: $!\n";
  13. binmode($INPUT);
  14.  
  15. open O, ">${emo}_data.txt";
  16.  
  17. seek $INPUT, 0x10, 0;
  18. my $skeleton_address = readu( $INPUT, "I", 4 );
  19.  
  20. seek $INPUT, $skeleton_address, 0;
  21.  
  22. my $total_nodes = readu( $INPUT, "I", 4 );
  23.  
  24. seek $INPUT, 4, 1; # unknown, small number
  25.  
  26. my $skeleton_start_offset = readu( $INPUT, "I", 4 );
  27. my $skeleton_name_addresses_offset = readu( $INPUT, "I", 4 );
  28.  
  29. seek $INPUT, 8, 1; # 0 0
  30.  
  31. seek $INPUT, 4, 1; # address for bunch of FF's
  32.  
  33. my $matrix_offset = readu( $INPUT, "I", 4 );
  34.  
  35. seek $INPUT, $skeleton_address + $skeleton_start_offset, 0;
  36.  
  37. open SMD, ">${emo}.smd";
  38. print SMD "version 1\nnodes\n";
  39.  
  40. my @node_parent;
  41. my @node_number;
  42. my @node_matrix;
  43. for( 0..$total_nodes-1 ) {
  44.     my $parent = readu( $INPUT, "s", 2 );
  45.     my $node_number = readu( $INPUT, "s", 2 );
  46.  
  47.     seek $INPUT, 12, 1; #skip unknowns (short + FF + FF + zeros)
  48.  
  49.     my @transformation_matrix = readu( $INPUT, "f16", 64 );
  50.     
  51.     push( @node_parent, $parent );
  52.     push( @node_number, $node_number );
  53.     push( @node_matrix, \@transformation_matrix );
  54.  
  55. }
  56. print O "\n";
  57.  
  58. seek $INPUT, $skeleton_address + $skeleton_name_addresses_offset, 0;
  59. my @skeleton_name_addresses = readu( $INPUT, "I$total_nodes", 4 * $total_nodes );
  60.  
  61. for( 0..$total_nodes-1 ) {
  62.     seek $INPUT, $skeleton_address + $skeleton_name_addresses[$_], 0;
  63.  
  64.     my $node_name = "";
  65.     my $char;
  66.     read( $INPUT, $char, 1 );
  67.     while( $char ne "\0" ) {
  68.         $node_name .= $char;
  69.         read( $INPUT, $char, 1 );
  70.     }
  71.     print SMD "$_ \"$node_name\" $node_parent[$_]\n";
  72.     printf O "%32s %3d - %9f %9f %9f %9f %9f %9f %9f %9f %9f %9f %9f %9f %9f %9f %9f %9f\n", $node_name, $node_parent[$_], @{$node_matrix[$_]};
  73. }
  74. print O "\n";
  75.  
  76. seek $INPUT, $skeleton_address + $matrix_offset, 0;
  77. print O "\n\nMATRIX DATA\n";
  78. for( 0..$total_nodes-1 ) {
  79.     my @matrix = readu( $INPUT, "f16", 64 );
  80.     printf O "%3d - %9f %9f %9f %9f %9f %9f %9f %9f %9f %9f %9f %9f %9f %9f %9f %9f\n", $_, @matrix;
  81. }
  82.  
  83.  
  84. print SMD "end\nskeleton\ntime 0\n";
  85.  
  86. # [m00 m01 m02]
  87. # [m10 m11 m12]
  88. # [m20 m21 m22]
  89. # heading = Math.atan2(-m.m20,m.m00);
  90. # bank = Math.atan2(-m.m12,m.m11);
  91. # attitude = Math.asin(m.m10);
  92.  
  93. for( 0..$total_nodes-1 ) {
  94.     my @translation = (-${$node_matrix[$_]}[12],${$node_matrix[$_]}[14],${$node_matrix[$_]}[13]);
  95.  
  96.     my $ry = atan2( -${$node_matrix[$_]}[2], ${$node_matrix[$_]}[0] );
  97.     my $rx = atan2( -${$node_matrix[$_]}[9], ${$node_matrix[$_]}[5] );
  98.     my $rz = asin_real( ${$node_matrix[$_]}[1] );
  99.  
  100.     printf SMD "%d  %f %f %f %f %f %f\n", $_, @translation, -$rx, $rz, $ry;
  101. }
  102.  
  103. print SMD "end\ntriangles\n";
  104.  
  105. seek $INPUT, 0x20, 0;
  106. my $num_emg_subfiles = readu( $INPUT, "S", 2 );
  107.  
  108. seek $INPUT, 0x28, 0;
  109. my @emg_file_addresses = readu( $INPUT, "I$num_emg_subfiles", 4 * $num_emg_subfiles );
  110.  
  111.  
  112. $emo =~ s/^(.+?)([^\\\/]+)$/\2/;
  113. $emo =~ /^(......)/;
  114. my $texture_prefix = $1 . "_";
  115.  
  116. for my $emg_address_i ( 0..$#emg_file_addresses ) {
  117.     print O "EMG #$emg_address_i\n";
  118.     print "\nEMG $emg_address_i/$#emg_file_addresses\n";
  119.     my $emg_address = $emg_file_addresses[$emg_address_i];
  120.     $emg_address += 0x20;
  121.     seek $INPUT, $emg_address, 0;
  122.     warn "Thing != 1" if readu( $INPUT, "I", 4 ) != 1; # 1
  123.     warn "Thing != 0x10" if readu( $INPUT, "I", 4 ) != 0x10; # 0x10
  124.     $emg_address += 0x10;
  125.     seek $INPUT, $emg_address + 6, 0;
  126.     warn "Thing2 != 1" if readu( $INPUT, "S", 2 ) != 1; # 1
  127.     warn "Thing2 != 0x10" if readu( $INPUT, "I", 4 ) != 0x10; # 0x10
  128.     $emg_address += 0x10;
  129.  
  130.     seek $INPUT, $emg_address, 0;
  131.  
  132.     readu( $INPUT, "I", 4 ); # 711
  133.     my $a_blocks = readu( $INPUT, "I", 4 ); # number of subblocks in BLOCK A
  134.     readu( $INPUT, "I", 4 ); # 0
  135.     my $a_block_address = readu( $INPUT, "I", 4 ); # BLOCK A address
  136.  
  137.     my $vertexblockcount = readu( $INPUT, "S", 2 );
  138.     my $vertexblocksize = readu( $INPUT, "S", 2 );
  139.     my $vertexblockaddress = readu( $INPUT, "I", 4 );
  140.  
  141.     my $b_blocks = readu( $INPUT, "S", 2 ); # should be 1, or else warn
  142.     my $b_subblocks = readu( $INPUT, "S", 2 );
  143.     my $b_block_address = readu( $INPUT, "S", 2 );
  144.  
  145.     seek $INPUT, $emg_address + 0x20, 0;
  146.     my @mesh_matrix = readu( $INPUT, "f12", 48 );
  147.     printf O "%10f %10f %10f %10f\n%10f %10f %10f %10f\n%10f %10f %10f %10f\n\n", @mesh_matrix;
  148.  
  149.     seek $INPUT, $emg_address + $a_block_address, 0;
  150.     my @a_block_addresses = readu( $INPUT, "I$a_blocks", 4 * $a_blocks );
  151.     my @texture_block;
  152.     for( 0..$a_blocks-1 ) {
  153.         seek $INPUT, $emg_address + $a_block_addresses[$_], 0;
  154.         my $num_textures = readu( $INPUT, "I", 4 );
  155.  
  156.         my $texture_num = readu( $INPUT, "n", 2 ); # Big Endian short
  157.         push( @texture_block, $texture_num );
  158.     }
  159.  
  160.     my @mesh_faces;
  161.     my @mesh_name;
  162.     my @mesh_nodes;
  163.     my @mesh_ids;
  164.     my @mesh_vector;
  165.     seek $INPUT, $emg_address + $b_block_address, 0;
  166.     my @b_subblock_addresses = readu( $INPUT, "I$b_subblocks", 4 * $b_subblocks );
  167.     print "Face addresses - @b_subblock_addresses\n";
  168.     for my $b_subblock_address( @b_subblock_addresses ) {
  169.         seek $INPUT, $emg_address + $b_subblock_address, 0;
  170.  
  171.         my @floats = readu( $INPUT, "f4", 16 );
  172.         push( @mesh_vector, \@floats );
  173.  
  174.         my $mesh_id = readu( $INPUT, "S", 2 );
  175.         my $num_faces = readu( $INPUT, "S", 2 );
  176.         my $num_shorts = readu( $INPUT, "S", 2 );
  177.         my $mesh_name = readu( $INPUT, "a32", 32 );
  178.         $mesh_name =~ s/\0+$//;
  179.  
  180.         push( @mesh_name, $mesh_name );
  181.         push( @mesh_ids, $mesh_id );
  182.  
  183.         print O "[$mesh_id] - $mesh_name : $num_faces Face Indices, $num_shorts Bones\n@floats\n\n";
  184.  
  185.         my @allfaces = readu( $INPUT, "S$num_faces", 2 * $num_faces );
  186.         print O "@allfaces\n\n";
  187.  
  188.         my @triangle_sets;
  189.         my $backface = 1;
  190.         for( 0..$#allfaces-2 ) {
  191.             my ($a, $b, $c) = ($allfaces[$_],$allfaces[$_+1],$allfaces[$_+2]);
  192.  
  193.             $backface = ($backface + 1) % 2;
  194.  
  195.             if( $a != $b && $a != $c && $b != $c ) {
  196.                 my @faceset;
  197.                 if( $backface ) {
  198.                     @faceset = ($c, $b, $a);
  199.                 } else {
  200.                     @faceset = ($a, $b, $c);
  201.                 }
  202.                 push( @triangle_sets, \@faceset );
  203.             }
  204.         }
  205.  
  206.         push( @mesh_faces, \@triangle_sets );
  207.  
  208.         my @allshorts = readu( $INPUT, "S$num_shorts", 2 * $num_shorts );
  209.  
  210.         push( @mesh_nodes, \@allshorts );
  211.         print O "@allshorts\n\n";
  212.         print O "----------------------------------------------------------\n";
  213.     }
  214.  
  215.     seek $INPUT, $emg_address + $vertexblockaddress, 0;
  216.     print O "Vertices : $vertexblockcount\n";
  217.     print O "        x         y         z        nx        ny        nz        tu        tv  unknown1  unknown2  unknown3   unknowns          bi0 bi1 bi2 bi3           w0        w1        w2\n";
  218.  
  219.     my @xyz;
  220.     my @normal;
  221.     my @uv;
  222.     my @nodes;
  223.     my @node_weights;
  224.     for( 0..$vertexblockcount-1 ) {
  225.  
  226.         my @floats;
  227.         if( $vertexblocksize == 64 ) {
  228.             @floats = readu( $INPUT, "f11", 44 );
  229.  
  230.             my @v_uc = ($floats[6],-$floats[7]);
  231.  
  232.             my @v_xyz = (-$floats[0],$floats[2],$floats[1]);
  233.             my @v_normal = (-$floats[3],$floats[5],$floats[4]);
  234.  
  235.             push( @uv, \@v_uc );
  236.             push( @xyz, \@v_xyz );
  237.             push( @normal, \@v_normal );
  238.  
  239.         } elsif( $vertexblocksize == 32 ) {    # used in skeleton EMO files
  240.             @floats = readu( $INPUT, "f3", 12 );
  241.  
  242.             my @v_xyz = ($floats[0],-$floats[2],$floats[1]);
  243.             my @v_uc = (0,0);
  244.             my @v_normal = (0,0,0);
  245.  
  246.             push( @uv, \@v_uc );
  247.             push( @xyz, \@v_xyz );
  248.             push( @normal, \@v_normal );
  249.  
  250.         } elsif( $vertexblocksize == 40 ) {    # used in shadow EMO files
  251.             @floats = readu( $INPUT, "f6", 24 );
  252.  
  253.             my @v_xyz = ($floats[0],-$floats[2],$floats[1]);
  254.             my @v_uc = (0,0);
  255.             my @v_normal = ($floats[3],-$floats[5],$floats[4]);
  256.  
  257.             push( @uv, \@v_uc );
  258.             push( @xyz, \@v_xyz );
  259.             push( @normal, \@v_normal );
  260.         }
  261.         printf O "%9f "x($#floats+1), @floats;
  262.  
  263.         if( $vertexblocksize != 40 ) {
  264.             my @unknownchars = readu( $INPUT, "C4", 4 );
  265.             printf O "| %3d %3d %3d %3d | ", @unknownchars;
  266.         }
  267.  
  268.         my @chars = readu( $INPUT, "C4", 4 );
  269.         printf O "%3d %3d %3d %3d | ", @chars;
  270.  
  271.         my @weight_floats = readu( $INPUT, "f3", 12 );
  272.         my $remaining_weight = 0;
  273.         my $total_weight = 0;
  274.         $total_weight += $_ for @weight_floats;
  275.         if( (1-$total_weight) > 0.001 ) {
  276.             $remaining_weight = 1-$total_weight;
  277.         }
  278.         push( @weight_floats, $remaining_weight );
  279.         printf O "%9f %9f %9f\n", @weight_floats;
  280.  
  281.         my %bone;
  282.         my @revised_nodes;
  283.         my @revised_weights;
  284.         for( 0..3 ) {
  285.             if( defined($bone{$chars[$_]}) ) {
  286.                 if( $weight_floats[$_] != 0 ) {
  287.                     print "Double Weight!\n";
  288.                     $revised_weights[$bone{$chars[$_]}] += $weight_floats[$_];
  289.                 }
  290.             } else {
  291.                 if( $weight_floats[$_] > 0 ) {
  292.                     push( @revised_nodes, $chars[$_] );
  293.                     push( @revised_weights, $weight_floats[$_] );
  294.                     $bone{$chars[$_]} = $#revised_nodes;
  295.                 } elsif( $weight_floats[$_] < 0 ) {
  296.                     print "NEGATIVE WEIGHT: $weight_floats[$_]\n";
  297.                 }
  298.                 
  299.             }
  300.         }
  301.         push( @nodes, \@revised_nodes );
  302.         push( @node_weights, \@revised_weights );
  303.     }
  304.  
  305.     for my $m( 0..$#mesh_faces ) {
  306.  
  307.         my @triangle_sets = @{$mesh_faces[$m]};
  308.  
  309.         print "Dumping mesh $m... ", $#triangle_sets+1, " triangle sets\n";
  310.  
  311.         for my $f( 0..$#triangle_sets ) {
  312.             my @face_vertices = @{$triangle_sets[$f]};
  313.  
  314.             print SMD "$mesh_name[$m]\\..\\$texture_prefix$texture_block[$mesh_ids[$m]].dds\n";
  315.             printf SMD "0 %10f %10f %10f %10f %10f %10f %10f %10f ", @{$xyz[$face_vertices[0]]}, @{$normal[$face_vertices[0]]}, @{$uv[$face_vertices[0]]};
  316.             print SMD ($#{$nodes[$face_vertices[0]]}+1);
  317.             for( 0..$#{$nodes[$face_vertices[0]]} ) {
  318.                 printf SMD " %3d %10f", $mesh_nodes[$m][${$nodes[$face_vertices[0]]}[$_]], ${$node_weights[$face_vertices[0]]}[$_];
  319.             }
  320.             print SMD "\n";
  321.  
  322.             printf SMD "0 %10f %10f %10f %10f %10f %10f %10f %10f ", @{$xyz[$face_vertices[1]]}, @{$normal[$face_vertices[1]]}, @{$uv[$face_vertices[1]]};
  323.             print SMD ($#{$nodes[$face_vertices[1]]}+1);
  324.             for( 0..$#{$nodes[$face_vertices[1]]} ) {
  325.                 printf SMD " %3d %10f", $mesh_nodes[$m][${$nodes[$face_vertices[1]]}[$_]], ${$node_weights[$face_vertices[1]]}[$_];
  326.             }
  327.             print SMD "\n";
  328.  
  329.             printf SMD "0 %10f %10f %10f %10f %10f %10f %10f %10f ", @{$xyz[$face_vertices[2]]}, @{$normal[$face_vertices[2]]}, @{$uv[$face_vertices[2]]};
  330.             print SMD ($#{$nodes[$face_vertices[2]]}+1);
  331.             for( 0..$#{$nodes[$face_vertices[2]]} ) {
  332.                 printf SMD " %3d %10f", $mesh_nodes[$m][${$nodes[$face_vertices[2]]}[$_]], ${$node_weights[$face_vertices[2]]}[$_];
  333.             }
  334.             print SMD "\n";
  335.         }
  336.     }
  337.  
  338.     print O "\n\nEMG FILE ENDED\n\n";
  339. }
  340.  
  341. print SMD "end\n";
  342. print "\nDone.\n\n";
  343. system("pause");
  344.  
  345.  
  346.  
  347.  
  348. sub readu {
  349.     my $temp;
  350.     read( $_[0], $temp, $_[2] );
  351.     return unpack( $_[1], $temp );
  352. }
  353.  
  354.