aboutsummaryrefslogtreecommitdiff
path: root/mp/src/devtools/bin/vsh_prep.pl
diff options
context:
space:
mode:
authorJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
committerJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
commit39ed87570bdb2f86969d4be821c94b722dc71179 (patch)
treeabc53757f75f40c80278e87650ea92808274aa59 /mp/src/devtools/bin/vsh_prep.pl
downloadsource-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz
source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/devtools/bin/vsh_prep.pl')
-rw-r--r--mp/src/devtools/bin/vsh_prep.pl1106
1 files changed, 1106 insertions, 0 deletions
diff --git a/mp/src/devtools/bin/vsh_prep.pl b/mp/src/devtools/bin/vsh_prep.pl
new file mode 100644
index 00000000..1ba8b6f1
--- /dev/null
+++ b/mp/src/devtools/bin/vsh_prep.pl
@@ -0,0 +1,1106 @@
+use String::CRC32;
+BEGIN {use File::Basename; push @INC, dirname($0); }
+require "valve_perl_helpers.pl";
+
+sub WriteHelperVar
+{
+ local( $name ) = shift;
+ local( $min ) = shift;
+ local( $max ) = shift;
+ local( $varname ) = "m_n" . $name;
+ local( $boolname ) = "m_b" . $name;
+ push @outputHeader, "private:\n";
+ push @outputHeader, "\tint $varname;\n";
+ push @outputHeader, "#ifdef _DEBUG\n";
+ push @outputHeader, "\tbool $boolname;\n";
+ push @outputHeader, "#endif\n";
+ push @outputHeader, "public:\n";
+ # int version of set function
+ push @outputHeader, "\tvoid Set" . $name . "( int i )\n";
+ push @outputHeader, "\t{\n";
+ if ( $min != $max )
+ {
+ push @outputHeader, "\t\tAssert( i >= $min && i <= $max );\n";
+ push @outputHeader, "\t\t$varname = i;\n";
+ push @outputHeader, "#ifdef _DEBUG\n";
+ push @outputHeader, "\t\t$boolname = true;\n";
+ push @outputHeader, "#endif\n";
+ }
+ push @outputHeader, "\t}\n";
+ # bool version of set function
+ push @outputHeader, "\tvoid Set" . $name . "( bool i )\n";
+ push @outputHeader, "\t{\n";
+ if ( $min != $max )
+ {
+# push @outputHeader, "\t\tAssert( i >= $min && i <= $max );\n";
+ push @outputHeader, "\t\t$varname = i ? 1 : 0;\n";
+ push @outputHeader, "#ifdef _DEBUG\n";
+ push @outputHeader, "\t\t$boolname = true;\n";
+ push @outputHeader, "#endif\n";
+ }
+ push @outputHeader, "\t}\n";
+}
+
+sub WriteStaticBoolExpression
+{
+ local( $prefix ) = shift;
+ local( $operator ) = shift;
+ for( $i = 0; $i < scalar( @staticDefineNames ); $i++ )
+ {
+ if( $i )
+ {
+ push @outputHeader, " $operator ";
+ }
+ local( $name ) = @staticDefineNames[$i];
+ local( $boolname ) = "m_b" . $name;
+ push @outputHeader, "$prefix$boolname";
+ }
+ push @outputHeader, ";\n";
+}
+
+sub WriteDynamicBoolExpression
+{
+ local( $prefix ) = shift;
+ local( $operator ) = shift;
+ for( $i = 0; $i < scalar( @dynamicDefineNames ); $i++ )
+ {
+ if( $i )
+ {
+ push @outputHeader, " $operator ";
+ }
+ local( $name ) = @dynamicDefineNames[$i];
+ local( $boolname ) = "m_b" . $name;
+ push @outputHeader, "$prefix$boolname";
+ }
+ push @outputHeader, ";\n";
+}
+
+sub WriteDynamicHelperClasses
+{
+ local( $basename ) = $fxc_filename;
+ $basename =~ s/\.fxc//i;
+ $basename =~ tr/A-Z/a-z/;
+ local( $classname ) = $basename . "_Dynamic_Index";
+ push @outputHeader, "class $classname\n";
+ push @outputHeader, "{\n";
+ for( $i = 0; $i < scalar( @dynamicDefineNames ); $i++ )
+ {
+ $name = $dynamicDefineNames[$i];
+ $min = $dynamicDefineMin[$i];
+ $max = $dynamicDefineMax[$i];
+ &WriteHelperVar( $name, $min, $max );
+ }
+ push @outputHeader, "public:\n";
+ push @outputHeader, "\t$classname()\n";
+ push @outputHeader, "\t{\n";
+ for( $i = 0; $i < scalar( @dynamicDefineNames ); $i++ )
+ {
+ $min = $dynamicDefineMin[$i];
+ $max = $dynamicDefineMax[$i];
+
+ local( $name ) = @dynamicDefineNames[$i];
+ local( $boolname ) = "m_b" . $name;
+ local( $varname ) = "m_n" . $name;
+ push @outputHeader, "#ifdef _DEBUG\n";
+ if ( $min != $max )
+ {
+ push @outputHeader, "\t\t$boolname = false;\n";
+ }
+ else
+ {
+ push @outputHeader, "\t\t$boolname = true;\n";
+ }
+ push @outputHeader, "#endif // _DEBUG\n";
+ push @outputHeader, "\t\t$varname = 0;\n";
+ }
+ push @outputHeader, "\t}\n";
+ push @outputHeader, "\tint GetIndex()\n";
+ push @outputHeader, "\t{\n";
+ push @outputHeader, "\t\t// Asserts to make sure that we aren't using any skipped combinations.\n";
+ foreach $skip (@perlskipcodeindividual)
+ {
+ $skip =~ s/\$/m_n/g;
+# push @outputHeader, "\t\tAssert( !( $skip ) );\n";
+ }
+ push @outputHeader, "\t\t// Asserts to make sure that we are setting all of the combination vars.\n";
+
+ push @outputHeader, "#ifdef _DEBUG\n";
+ if( scalar( @dynamicDefineNames ) > 0 )
+ {
+ push @outputHeader, "\t\tbool bAllDynamicVarsDefined = ";
+ WriteDynamicBoolExpression( "", "&&" );
+ }
+ if( scalar( @dynamicDefineNames ) > 0 )
+ {
+ push @outputHeader, "\t\tAssert( bAllDynamicVarsDefined );\n";
+ }
+ push @outputHeader, "#endif // _DEBUG\n";
+
+ if( $spewCombos && scalar( @dynamicDefineNames ) )
+ {
+ push @outputHeader, &CreateCCodeToSpewDynamicCombo();
+ }
+ push @outputHeader, "\t\treturn ";
+ local( $scale ) = 1;
+ for( $i = 0; $i < scalar( @dynamicDefineNames ); $i++ )
+ {
+ local( $name ) = @dynamicDefineNames[$i];
+ local( $varname ) = "m_n" . $name;
+ push @outputHeader, "( $scale * $varname ) + ";
+ $scale *= $dynamicDefineMax[$i] - $dynamicDefineMin[$i] + 1;
+ }
+ push @outputHeader, "0;\n";
+ push @outputHeader, "\t}\n";
+ push @outputHeader, "};\n";
+}
+
+sub WriteStaticHelperClasses
+{
+ local( $basename ) = $fxc_filename;
+ $basename =~ s/\.fxc//i;
+ $basename =~ tr/A-Z/a-z/;
+ local( $classname ) = $basename . "_Static_Index";
+ push @outputHeader, "class $classname\n";
+ push @outputHeader, "{\n";
+ for( $i = 0; $i < scalar( @staticDefineNames ); $i++ )
+ {
+ $name = $staticDefineNames[$i];
+ $min = $staticDefineMin[$i];
+ $max = $staticDefineMax[$i];
+ &WriteHelperVar( $name, $min, $max );
+ }
+ push @outputHeader, "public:\n";
+ push @outputHeader, "\t$classname()\n";
+ push @outputHeader, "\t{\n";
+ for( $i = 0; $i < scalar( @staticDefineNames ); $i++ )
+ {
+ $min = $staticDefineMin[$i];
+ $max = $staticDefineMax[$i];
+
+ local( $name ) = @staticDefineNames[$i];
+ local( $boolname ) = "m_b" . $name;
+ local( $varname ) = "m_n" . $name;
+
+ push @outputHeader, "#ifdef _DEBUG\n";
+ if ( $min != $max )
+ {
+ push @outputHeader, "\t\t$boolname = false;\n";
+ }
+ else
+ {
+ push @outputHeader, "\t\t$boolname = true;\n";
+ }
+ push @outputHeader, "#endif // _DEBUG\n";
+ push @outputHeader, "\t\t$varname = 0;\n";
+ }
+ push @outputHeader, "\t}\n";
+ push @outputHeader, "\tint GetIndex()\n";
+ push @outputHeader, "\t{\n";
+ push @outputHeader, "\t\t// Asserts to make sure that we aren't using any skipped combinations.\n";
+ foreach $skip (@perlskipcodeindividual)
+ {
+ $skip =~ s/\$/m_n/g;
+# push @outputHeader, "\t\tAssert( !( $skip ) );\n";
+ }
+ push @outputHeader, "\t\t// Asserts to make sure that we are setting all of the combination vars.\n";
+
+ push @outputHeader, "#ifdef _DEBUG\n";
+ if( scalar( @staticDefineNames ) > 0 )
+ {
+ push @outputHeader, "\t\tbool bAllStaticVarsDefined = ";
+ WriteStaticBoolExpression( "", "&&" );
+
+ }
+ if( scalar( @staticDefineNames ) > 0 )
+ {
+ push @outputHeader, "\t\tAssert( bAllStaticVarsDefined );\n";
+ }
+ push @outputHeader, "#endif // _DEBUG\n";
+
+ if( $spewCombos && scalar( @staticDefineNames ) )
+ {
+ push @outputHeader, &CreateCCodeToSpewStaticCombo();
+ }
+ push @outputHeader, "\t\treturn ";
+ local( $scale ) = 1;
+ for( $i = 0; $i < scalar( @dynamicDefineNames ); $i++ )
+ {
+ $scale *= $dynamicDefineMax[$i] - $dynamicDefineMin[$i] + 1;
+ }
+ for( $i = 0; $i < scalar( @staticDefineNames ); $i++ )
+ {
+ local( $name ) = @staticDefineNames[$i];
+ local( $varname ) = "m_n" . $name;
+ push @outputHeader, "( $scale * $varname ) + ";
+ $scale *= $staticDefineMax[$i] - $staticDefineMin[$i] + 1;
+ }
+ push @outputHeader, "0;\n";
+ push @outputHeader, "\t}\n";
+ push @outputHeader, "};\n";
+}
+
+sub CreateFuncToSetPerlVars
+{
+ local( $out ) = "";
+
+ $out .= "sub SetPerlVarsFunc\n";
+ $out .= "{\n";
+ $out .= " local( \$combo ) = shift;\n";
+ $out .= " local( \$i );\n";
+ local( $i );
+ for( $i = 0; $i < scalar( @dynamicDefineNames ); \$i++ )
+ {
+ $out .= " \$$dynamicDefineNames[$i] = \$combo % ";
+ $out .= ( $dynamicDefineMax[$i] - $dynamicDefineMin[$i] + 1 ) + $dynamicDefineMin[$i];
+ $out .= ";\n";
+ $out .= " \$combo = \$combo / " . ( $dynamicDefineMax[$i] - $dynamicDefineMin[$i] + 1 ) . ";\n";
+ }
+ for( $i = 0; $i < scalar( @staticDefineNames ); \$i++ )
+ {
+ $out .= " \$$staticDefineNames[$i] = \$combo % ";
+ $out .= ( $staticDefineMax[$i] - $staticDefineMin[$i] + 1 ) + $staticDefineMin[$i];
+ $out .= ";\n";
+ $out .= " \$combo = \$combo / " . ( $staticDefineMax[$i] - $staticDefineMin[$i] + 1 ) . ";\n";
+ }
+ $out .= "}\n";
+
+# print $out;
+ eval $out;
+}
+
+# These sections can be interchanged to enable profiling.
+#$ShowTimers = 1;
+#use Time::HiRes;
+#sub SampleTime()
+#{
+# return Time::HiRes::time();
+#}
+
+$ShowTimers = 0;
+sub SampleTime() { return 0; }
+
+$total_start_time = SampleTime();
+
+# NOTE: These must match the same values in macros.vsh!
+$vPos = "v0";
+$vBoneWeights = "v1";
+$vBoneIndices = "v2";
+$vNormal = "v3";
+if( $g_x360 )
+{
+ $vPosFlex = "v4";
+ $vNormalFlex = "v13";
+}
+$vColor = "v5";
+$vSpecular = "v6";
+$vTexCoord0 = "v7";
+$vTexCoord1 = "v8";
+$vTexCoord2 = "v9";
+$vTexCoord3 = "v10";
+$vTangentS = "v11";
+$vTangentT = "v12";
+$vUserData = "v14";
+
+sub ReadInputFileWithLineInfo
+{
+ local( $base_filename ) = shift;
+
+ local( *INPUT );
+ local( @output );
+
+ # Look in the stdshaders directory, followed by the current directory.
+ # (This is for the SDK, since some of its files are under stdshaders).
+ local( $filename ) = $base_filename;
+ if ( !-e $filename )
+ {
+ $filename = "$g_SourceDir\\materialsystem\\stdshaders\\$base_filename";
+ if ( !-e $filename )
+ {
+ die "\nvsh_prep.pl ERROR: missing include file: $filename.\n\n";
+ }
+ }
+
+ open INPUT, "<$filename" || die;
+
+ local( $line );
+ local( $linenum ) = 1;
+ while( $line = <INPUT> )
+ {
+ $line =~ s/\n//g;
+ local( $postfix ) = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
+ $postfix .= "; LINEINFO($filename)($linenum)\n";
+ if( $line =~ m/\#include\s+\"(.*)\"/i )
+ {
+ push @output, &ReadInputFileWithLineInfo( $1 );
+ }
+ else
+ {
+ push @output, $line . $postfix;
+ }
+ $linenum++;
+ }
+
+ close INPUT;
+ return @output;
+}
+
+sub ReadInputFileWithoutLineInfo
+{
+ local( $base_filename ) = shift;
+
+ local( *INPUT );
+ local( @output );
+
+ # Look in the stdshaders directory, followed by the current directory.
+ # (This is for the SDK, since some of its files are under stdshaders).
+ local( $filename ) = $base_filename;
+ if ( !-e $filename )
+ {
+ $filename = "$g_SourceDir\\materialsystem\\stdshaders\\$base_filename";
+ if ( !-e $filename )
+ {
+ die "\nERROR: missing include file: $filename.\n\n";
+ }
+ }
+
+ open INPUT, "<$filename" || die;
+
+ local( $line );
+ while( $line = <INPUT> )
+ {
+ if( $line =~ m/\#include\s+\"(.*)\"/i )
+ {
+ push @output, &ReadInputFileWithoutLineInfo( $1 );
+ }
+ else
+ {
+ push @output, $line;
+ }
+ }
+
+ close INPUT;
+ return @output;
+}
+
+sub IsPerl
+{
+ local( $line ) = shift;
+ if( $line =~ m/^\s*sub.*\,/ )
+ {
+ return 0;
+ }
+ if( $line =~ m/^\#include/ ||
+ $line =~ m/^\#define/ ||
+ $line =~ m/^\#undef/ ||
+ $line =~ m/^\#ifdef/ ||
+ $line =~ m/^\#ifndef/ ||
+ $line =~ m/^\#else/ ||
+ $line =~ m/^\#endif/ ||
+ $line =~ m/^\#error/
+ )
+ {
+ return 0;
+ }
+ if( $line =~ m/^\s*if\s*\(/ ||
+ $line =~ m/^\s*else/ ||
+ $line =~ m/^\s*elsif/ ||
+ $line =~ m/^\s*for\s*\(/ ||
+ $line =~ m/^\s*\{/ ||
+ $line =~ m/^sub\s*/ ||
+ $line =~ m/^\s*\}/ ||
+ $line =~ m/^\s*\&/ ||
+ $line =~ m/^\s*\#/ ||
+ $line =~ m/^\s*\$/ ||
+ $line =~ m/^\s*print/ ||
+ $line =~ m/^\s*return/ ||
+ $line =~ m/^\s*exit/ ||
+ $line =~ m/^\s*die/ ||
+ $line =~ m/^\s*eval/ ||
+ $line =~ m/^\s*local/ ||
+ $line =~ m/^\s*my\s+/ ||
+ $line =~ m/^\s*@/ ||
+ $line =~ m/^\s*alloc\s+/ ||
+ $line =~ m/^\s*free\s+/
+ )
+ {
+ return 1;
+ }
+ return 0;
+}
+
+# translate the output into something that takes us back to the source line
+# that we care about in msdev
+sub TranslateErrorMessages
+{
+ local( $origline );
+ while( $origline = shift )
+ {
+ if( $origline =~ m/(.*)\((\d+)\)\s*:\s*(.*)$/i )
+ {
+ local( $filename ) = $1;
+ local( $linenum ) = $2;
+ local( $error ) = $3;
+ local( *FILE );
+ open FILE, "<$filename" || die;
+ local( $i );
+ local( $line );
+ for( $i = 1; $i < $linenum; $i++ )
+ {
+ $line = <FILE>;
+ }
+ if( $line =~ m/LINEINFO\((.*)\)\((.*)\)/ )
+ {
+ print "$1\($2\) : $error\n";
+ my $num = $linenum - 1;
+ print "$filename\($num\) : original error location\n";
+ }
+ close FILE;
+ }
+ else
+ {
+ $origline =~ s/successful compile\!.*//gi;
+ if( !( $origline =~ m/^\s*$/ ) )
+ {
+# print "WTF: $origline\n";
+ }
+ }
+ }
+}
+
+
+sub CountInstructions
+{
+ local( $line );
+ local( $count ) = 0;
+ while( $line = shift )
+ {
+ # get rid of comments
+ $line =~ s/;.*//gi;
+ $line =~ s/\/\/.*//gi;
+ # skip the vs1.1 statement
+ $line =~ s/^\s*vs.*//gi;
+ # if there's any text left, it's an instruction
+ if( $line =~ /\S/gi )
+ {
+ $count++;
+ }
+ }
+ return $count;
+}
+
+
+%compiled = ();
+
+sub UsesRegister
+{
+ my $registerName = shift;
+ my $str = shift;
+
+ # Cache a compiled RE for each register name. This makes UsesRegister about 2.5x faster.
+ if ( !$compiled{$registerName} )
+ {
+ $compiled{$registerName} = qr/\b$registerName\b/;
+ }
+
+ $ret = 0;
+ if( $str =~ /$compiled{$registerName}/gi )
+ {
+ $ret = 1;
+ }
+
+ return $ret;
+}
+
+sub PadString
+{
+ local( $str ) = shift;
+ local( $desiredLen ) = shift;
+ local( $len ) = length $str;
+ while( $len < $desiredLen )
+ {
+ $str .= " ";
+ $len++;
+ }
+ return $str;
+}
+
+sub FixupAllocateFree
+{
+ local( $line ) = shift;
+ $line =~ s/\&AllocateRegister\s*\(\s*\\(\S+)\s*\)/&AllocateRegister( \\$1, \"\\$1\" )/g;
+ $line =~ s/\&FreeRegister\s*\(\s*\\(\S+)\s*\)/&FreeRegister( \\$1, \"\\$1\" )/g;
+ $line =~ s/alloc\s+(\S+)\s*/local( $1 ); &AllocateRegister( \\$1, \"\\$1\" );/g;
+ $line =~ s/free\s+(\S+)\s*/&FreeRegister( \\$1, \"\\$1\" );/g;
+ return $line;
+}
+
+sub TranslateDXKeywords
+{
+ local( $line ) = shift;
+ $line =~ s/\bENDIF\b/endif/g;
+ $line =~ s/\bIF\b/if/g;
+ $line =~ s/\bELSE\b/else/g;
+
+ return $line;
+}
+
+# This is used to make the generated pl files all pretty.
+sub GetLeadingWhiteSpace
+{
+ local( $str ) = shift;
+ if( $str =~ m/^;\S/ || $str =~ m/^; \S/ )
+ {
+ return "";
+ }
+ $str =~ s/^;/ /g; # count a leading ";" as whitespace as far as this is concerned.
+ $str =~ m/^(\s*)/;
+ return $1;
+}
+
+$g_dx9 = 1;
+$g_SourceDir = "..\\..";
+
+while( 1 )
+{
+ $filename = shift;
+
+ if ( $filename =~ m/-source/i )
+ {
+ $g_SourceDir = shift;
+ }
+ elsif( $filename =~ m/-x360/i )
+ {
+ $g_x360 = 1;
+ }
+ else
+ {
+ last;
+ }
+}
+
+$filename =~ s/-----.*$//;
+
+
+#
+# Get the shader binary version number from a header file.
+#
+open FILE, "<$g_SourceDir\\public\\materialsystem\\shader_vcs_version.h" || die;
+while( $line = <FILE> )
+{
+ if( $line =~ m/^\#define\s+SHADER_VCS_VERSION_NUMBER\s+(\d+)\s*$/ )
+ {
+ $shaderVersion = $1;
+ last;
+ }
+}
+if( !defined $shaderVersion )
+{
+ die "couldn't get shader version from shader_vcs_version.h";
+}
+close FILE;
+
+
+if( $g_x360 )
+{
+ $vshtmp = "vshtmp9_360_tmp";
+}
+else
+{
+ $vshtmp = "vshtmp9_tmp";
+}
+
+if( !stat $vshtmp )
+{
+ mkdir $vshtmp, 0777 || die $!;
+}
+
+# suck in all files, including $include files.
+@input = &ReadInputFileWithLineInfo( $filename );
+
+sub CalcNumCombos
+{
+ local( $i, $numCombos );
+ $numCombos = 1;
+ for( $i = 0; $i < scalar( @dynamicDefineNames ); $i++ )
+ {
+ $numCombos *= $dynamicDefineMax[$i] - $dynamicDefineMin[$i] + 1;
+ }
+ for( $i = 0; $i < scalar( @staticDefineNames ); $i++ )
+ {
+ $numCombos *= $staticDefineMax[$i] - $staticDefineMin[$i] + 1;
+ }
+ return $numCombos;
+}
+
+sub CalcNumDynamicCombos
+{
+ local( $i, $numCombos );
+ $numCombos = 1;
+ for( $i = 0; $i < scalar( @dynamicDefineNames ); $i++ )
+ {
+ $numCombos *= $dynamicDefineMax[$i] - $dynamicDefineMin[$i] + 1;
+ }
+ return $numCombos;
+}
+
+# READ THE TOP OF THE FILE TO FIND SHADER COMBOS
+foreach $_ ( @input )
+{
+ next if( m/^\s*$/ );
+# last if( !m,^//, );
+ s,^//\s*,,;
+ if( m/\s*STATIC\s*\:\s*\"(.*)\"\s+\"(\d+)\.\.(\d+)\"/ )
+ {
+ local( $name, $min, $max );
+ $name = $1;
+ $min = $2;
+ $max = $3;
+# print "\"$name\" \"$min..$max\"\n";
+ if (/\[(.*)\]/)
+ {
+ $platforms=$1;
+ next if ( ($g_x360) && (!($platforms=~/XBOX/i)) );
+ next if ( (!$g_x360) && (!($platforms=~/PC/i)) );
+ }
+ push @staticDefineNames, $name;
+ push @staticDefineMin, $min;
+ push @staticDefineMax, $max;
+ }
+ elsif( m/\s*DYNAMIC\s*\:\s*\"(.*)\"\s+\"(\d+)\.\.(\d+)\"/ )
+ {
+ local( $name, $min, $max );
+ $name = $1;
+ $min = $2;
+ $max = $3;
+ if (/\[(.*)\]/)
+ {
+ $platforms=$1;
+ next if ( ($g_x360) && (!($platforms=~/XBOX/i)) );
+ next if ( (!$g_x360) && (!($platforms=~/PC/i)) );
+ }
+# print "\"$name\" \"$min..$max\"\n";
+ push @dynamicDefineNames, $name;
+ push @dynamicDefineMin, $min;
+ push @dynamicDefineMax, $max;
+ }
+}
+
+# READ THE WHOLE FILE AND FIND SKIP STATEMENTS
+foreach $_ ( @input )
+{
+ if( m/^\s*\#\s*SKIP\s*\:\s*(.*\S+)\s*\; LINEINFO.*$/ )
+ {
+ $perlskipcode .= "(" . $1 . ")||";
+ push @perlskipcodeindividual, $1;
+ }
+}
+if( defined $perlskipcode )
+{
+ $perlskipcode .= "0";
+ $perlskipcode =~ s/\n//g;
+}
+else
+{
+ $perlskipcode = "0";
+}
+
+#print $perlskipcode . "\n";
+
+
+# Translate the input into a perl program that'll unroll everything and
+# substitute variables.
+while( $inputLine = shift @input )
+{
+ $inputLine =~ s/\n//g;
+ # leave out lines that are only whitespace.
+ if( $inputLine =~ m/^\s*; LINEINFO.*$/ )
+ {
+ next;
+ }
+ local( $inputLineNoLineNum ) = $inputLine;
+ $inputLineNoLineNum =~ s/; LINEINFO.*//gi;
+ if( &IsPerl( $inputLineNoLineNum ) )
+ {
+ $inputLineNoLineNum = &FixupAllocateFree( $inputLineNoLineNum );
+ push @outputProgram, $inputLineNoLineNum . "\n";
+ }
+ else
+ {
+ # make asm lines that have quotes in them not barf.
+ $inputLine =~ s/\"/\\\"/g;
+ $inputLine = &TranslateDXKeywords( $inputLine );
+ push @outputProgram, &GetLeadingWhiteSpace( $inputLine ) . "push \@output, \"" .
+ $inputLine . "\\n\";\n";
+ }
+}
+
+$outputProgram = join "", @outputProgram;
+
+$filename_base = $filename;
+$filename_base =~ s/\.vsh//i;
+
+open DEBUGOUT, ">$vshtmp" . "/$filename_base.pl" || die;
+print DEBUGOUT $outputProgram;
+close DEBUGOUT;
+
+# Make a function called OutputProgram()
+$bigProg = "sub OutputProgram { " . $outputProgram . "}";
+eval( $bigProg );
+
+
+#print $outputProgram;
+
+#push @finalheader, "// hack to force dependency checking\n";
+#push @finalheader, "\#ifdef NEVER\n";
+#push @finalheader, "\#include \"" . $filename_base . "\.vsh\"\n";
+#push @finalheader, "\#include \"..\\..\\devtools\\bin\\vsh_prep.pl\"\n";
+#push @finalheader, "\#endif\n";
+
+%g_TimingBlocks = ();
+$main_start_time = SampleTime();
+
+$numCombos = &CalcNumCombos();
+$numDynamicCombos = &CalcNumDynamicCombos();
+#print "$numCombos total combos\n";
+#print "$numDynamicCombos dynamic combos\n";
+#print $numCombos / $numDynamicCombos . " static combos\n";
+
+# Write out the C++ helper class for picking shader combos
+$fxc_filename = $filename_base;
+&WriteStaticHelperClasses();
+&WriteDynamicHelperClasses();
+
+# Create a subroutine out of $perlskipcode
+$perlskipfunc = "sub SkipCombo { return $perlskipcode; }\n";
+#print $perlskipfunc;
+
+eval $perlskipfunc;
+&CreateFuncToSetPerlVars();
+
+my $incfilename = "$vshtmp/$filename_base" . ".inc";
+
+# Write the inc file that has indexing helpers, etc.
+&WriteFile( $incfilename, join( "", @outputHeader ) );
+
+
+# Run the output program for all the combinations of bones and lights.
+print "$filename_base.vsh\n";
+for( $i = 0; $i < $numCombos; $i++ )
+{
+# print "combo $i\n";
+ &SetPerlVarsFunc( $i );
+ local( $compileFailed );
+ $ret = &SkipCombo;
+ if( !defined $ret )
+ {
+ die "$@\n";
+ }
+ if( $ret )
+ {
+ # skip this combo!
+ $compileFailed = 1;
+ $numSkipped++;
+ next;
+ }
+
+ $start = SampleTime();
+
+ $g_usesPos = 0;
+ $g_usesPosFlex = 0;
+ $g_usesBoneWeights = 0;
+ $g_usesBoneIndices = 0;
+ $g_usesNormal = 0;
+ $g_usesNormalFlex = 0;
+ $g_usesColor = 0;
+ $g_usesSpecular = 0;
+ $g_usesTexCoord0 = 0;
+ $g_usesTexCoord1 = 0;
+ $g_usesTexCoord2 = 0;
+ $g_usesTexCoord3 = 0;
+ $g_usesTangentS = 0;
+ $g_usesTangentT = 0;
+ $g_usesUserData = 0;
+
+ undef @output;
+
+ $g_TimingBlocks{"inner1"} += SampleTime() - $start;
+
+ $eval_start_time = SampleTime();
+ &OutputProgram();
+ $eval_total_time += (SampleTime() - $eval_start_time);
+
+ $start = SampleTime();
+
+ # Strip out comments once so we don't have to do it in all the UsesRegister calls.
+ @stripped = @output;
+ map
+ {
+ $_ =~ s/;.*//gi;
+ $_ =~ s/\/\/.*//gi;
+ } @stripped;
+ my $strippedStr = join( "", @stripped );
+
+ $g_TimingBlocks{"inner2"} += SampleTime() - $start;
+
+ $start = SampleTime();
+
+ # Have to make another pass through after we know which v registers are used. . yuck.
+ $g_usesPos = &UsesRegister( $vPos, $strippedStr );
+ if( $g_x360 )
+ {
+ $g_usesPosFlex = &UsesRegister( $vPosFlex, $strippedStr );
+ $g_usesNormalFlex = &UsesRegister( $vNormalFlex, $strippedStr );
+ }
+ $g_usesBoneWeights = &UsesRegister( $vBoneWeights, $strippedStr );
+ $g_usesBoneIndices = &UsesRegister( $vBoneIndices, $strippedStr );
+ $g_usesNormal = &UsesRegister( $vNormal, $strippedStr );
+ $g_usesColor = &UsesRegister( $vColor, $strippedStr );
+ $g_usesSpecular = &UsesRegister( $vSpecular, $strippedStr );
+ $g_usesTexCoord0 = &UsesRegister( $vTexCoord0, $strippedStr );
+ $g_usesTexCoord1 = &UsesRegister( $vTexCoord1, $strippedStr );
+ $g_usesTexCoord2 = &UsesRegister( $vTexCoord2, $strippedStr );
+ $g_usesTexCoord3 = &UsesRegister( $vTexCoord3, $strippedStr );
+ $g_usesTangentS = &UsesRegister( $vTangentS, $strippedStr );
+ $g_usesTangentT = &UsesRegister( $vTangentT, $strippedStr );
+ $g_usesUserData = &UsesRegister( $vUserData, $strippedStr );
+ undef @output;
+
+ $g_TimingBlocks{"inner2"} += SampleTime() - $start;
+
+ $eval_start_time = SampleTime();
+ # Running OutputProgram generates $outfilename
+ &OutputProgram();
+ $eval_total_time += (SampleTime() - $eval_start_time);
+
+ $start = SampleTime();
+
+ &CheckUnfreedRegisters();
+
+ for( $j = 0; $j < scalar( @output ); $j++ )
+ {
+ # remove whitespace from the beginning of each line.
+ $output[$j] =~ s/^\s+//;
+ # remove LINEINFO from empty lines.
+ $output[$j] =~ s/^; LINEINFO.*//;
+ }
+
+ $g_TimingBlocks{"inner3"} += SampleTime() - $start;
+ $start = SampleTime();
+
+
+ $outfilename_base = $filename_base . "_" . $i;
+
+ # $outfilename is the name of the file generated from executing the perl code
+ # for this shader. This file is generated once per combo.
+ # We will assemble this shader with vsa.exe.
+ $outfilename = "$vshtmp\\" . $outfilename_base . ".tmp";
+
+# $outhdrfilename = "$vshtmp\\" . $outfilename_base . ".h";
+# unlink $outhdrfilename;
+
+ open OUTPUT, ">$outfilename" || die;
+ print OUTPUT @output;
+ close OUTPUT;
+
+ $g_TimingBlocks{"inner4"} += SampleTime() - $start;
+ $start = SampleTime();
+
+ local( $instructionCount ) = &CountInstructions( @output );
+ $g_TimingBlocks{"inner5"} += SampleTime() - $start;
+
+ local( $debug );
+
+ $debug = 1;
+# for( $debug = 1; $debug >= 0; $debug-- )
+ {
+ # assemble the vertex shader
+ unlink "shader$i.o";
+ if( $g_x360 )
+ {
+ $vsa = "..\\..\\x360xdk\\bin\\win32\\vsa";
+ }
+ else
+ {
+ $vsa = "..\\..\\dx9sdk\\utilities\\vsa";
+ }
+ $vsadebug = "$vsa /nologo /Foshader$i.o $outfilename";
+ $vsanodebug = "$vsa /nologo /Foshader$i.o $outfilename";
+
+ $vsa_start_time = SampleTime();
+
+ if( $debug )
+ {
+# print $vsadebug . "\n";
+ @vsaoutput = `$vsadebug 2>&1`;
+# print @vsaoutput;
+ }
+ else
+ {
+ @vsaoutput = `$vsanodebug 2>&1`;
+ }
+
+ $vsa_total_time += SampleTime() - $vsa_start_time;
+
+ $start = SampleTime();
+
+ &TranslateErrorMessages( @vsaoutput );
+
+ $g_TimingBlocks{"inner6"} += SampleTime() - $start;
+
+ push @finalheader, @hdr;
+ }
+}
+
+
+$main_total_time = SampleTime() - $main_start_time;
+
+# stick info about the shaders at the end of the inc file.
+push @finalheader, "static PrecompiledShaderByteCode_t $filename_base" . "_vertex_shaders[] = {\n";
+for( $i = 0; $i < $numCombos; $i++ )
+{
+ $outfilename_base = $filename_base . "_" . $i;
+ push @finalheader, "{ $outfilename_base, sizeof( $outfilename_base ) },\n";
+}
+push @finalheader, "};\n";
+
+
+push @finalheader, "struct $filename_base" . "_VertexShader_t : public PrecompiledShader_t\n";
+push @finalheader, "{\n";
+push @finalheader, "\t$filename_base" . "_VertexShader_t()\n";
+push @finalheader, "\t{\n";
+push @finalheader, "\t\tm_nFlags = 0;\n";
+
+$flags = 0;
+#push @finalheader, "\t\tppVertexShaders = $filename_base" . "_vertex_shaders;\n";
+push @finalheader, "\t\tm_pByteCode = $filename_base" . "_vertex_shaders;\n";
+push @finalheader, "\t\tm_pName = \"$filename_base\";\n";
+push @finalheader, "\t\tm_nShaderCount = " . ( $maxNumBones + 1 ) * $totalFogCombos * $totalLightCombos . ";\n";
+push @finalheader, "\t\tm_nDynamicCombos = m_nShaderCount;\n";
+push @finalheader, "\t\tGetShaderDLL()->InsertPrecompiledShader( PRECOMPILED_VERTEX_SHADER, this );\n";
+push @finalheader, "\t}\n";
+push @finalheader, "\tvirtual const PrecompiledShaderByteCode_t &GetByteCode( int shaderID )\n";
+push @finalheader, "\t{\n";
+push @finalheader, "\t\treturn m_pByteCode[shaderID];\n";
+push @finalheader, "\t}\n";
+push @finalheader, "};\n";
+push @finalheader, "static $filename_base" . "_VertexShader_t $filename_base" . "_VertexShaderInstance;\n";
+
+# Write the final header file with the compiled vertex shader programs.
+$finalheadername = "$vshtmp\\" . $filename_base . ".inc";
+#print "writing $finalheadername\n";
+#open FINALHEADER, ">$finalheadername" || die;
+#print FINALHEADER @finalheader;
+#close FINALHEADER;
+
+&MakeDirHier( "shaders/vsh" );
+
+my $vcsName = "";
+if( $g_x360 )
+{
+ $vcsName = $filename_base . ".360.vcs";
+}
+else
+{
+ $vcsName = $filename_base . ".vcs";
+}
+open COMPILEDSHADER, ">shaders/vsh/$vcsName" || die;
+binmode( COMPILEDSHADER );
+
+#
+# Write out the part of the header that we know. . we'll write the rest after writing the object code.
+#
+
+# Pack arguments
+my $sInt = "i";
+my $uInt = "I";
+if ( $g_x360 )
+{
+ # Change arguments to "big endian long"
+ $sInt = "N";
+ $uInt = "N";
+}
+
+my $undecoratedinput = join "", &ReadInputFileWithoutLineInfo( $filename );
+#print STDERR "undecoratedinput: $undecoratedinput\n";
+my $crc = crc32( $undecoratedinput );
+#print STDERR "crc for $filename: $crc\n";
+
+# version
+print COMPILEDSHADER pack $sInt, 4;
+# totalCombos
+print COMPILEDSHADER pack $sInt, $numCombos;
+# dynamic combos
+print COMPILEDSHADER pack $sInt, $numDynamicCombos;
+# flags
+print COMPILEDSHADER pack $uInt, $flags;
+# centroid mask
+print COMPILEDSHADER pack $uInt, 0;
+# reference size
+print COMPILEDSHADER pack $uInt, 0;
+# crc32 of the source code
+print COMPILEDSHADER pack $uInt, $crc;
+
+my $beginningOfDir = tell COMPILEDSHADER;
+
+# Write out a blank directionary. . we'll fill it in later.
+for( $i = 0; $i < $numCombos; $i++ )
+{
+ # offset from beginning of file.
+ print COMPILEDSHADER pack $sInt, 0;
+ # size
+ print COMPILEDSHADER pack $sInt, 0;
+}
+
+my $startByteCode = tell COMPILEDSHADER;
+my @byteCodeStart;
+my @byteCodeSize;
+
+# Write out the shader object code.
+for( $shaderCombo = 0; $shaderCombo < $numCombos; $shaderCombo++ )
+{
+ my $filename = "shader$shaderCombo\.o";
+ my $filesize = (stat $filename)[7];
+ $byteCodeStart[$shaderCombo] = tell COMPILEDSHADER;
+ $byteCodeSize[$shaderCombo] = $filesize;
+ open SHADERBYTECODE, "<$filename" || die;
+ binmode SHADERBYTECODE;
+ my $bin;
+ my $numread = read SHADERBYTECODE, $bin, $filesize;
+# print "filename: $filename numread: $numread filesize: $filesize\n";
+ close SHADERBYTECODE;
+ unlink $filename;
+
+ print COMPILEDSHADER $bin;
+}
+
+# Seek back to the directory and write it out.
+seek COMPILEDSHADER, $beginningOfDir, 0;
+for( $i = 0; $i < $numCombos; $i++ )
+{
+ # offset from beginning of file.
+ print COMPILEDSHADER pack $sInt, $byteCodeStart[$i];
+ # size
+ print COMPILEDSHADER pack $sInt, $byteCodeSize[$i];
+}
+
+close COMPILEDSHADER;
+
+$total_time = SampleTime() - $total_start_time;
+
+if ( $ShowTimers )
+{
+ print "\n\n";
+ print sprintf( "Main loop time : %0.4f sec, (%0.2f%%)\n", $main_total_time, 100*$main_total_time / $total_time );
+ print sprintf( "Inner1 time : %0.4f sec, (%0.2f%%)\n", $inner1_total_time, 100*$inner1_total_time / $total_time );
+ print sprintf( "VSA time : %0.4f sec, (%0.2f%%)\n", $vsa_total_time, 100*$vsa_total_time / $total_time );
+ print sprintf( "eval() time : %0.4f sec, (%0.2f%%)\n", $eval_total_time, 100*$eval_total_time / $total_time );
+ print sprintf( "UsesRegister time: %0.4f sec, (%0.2f%%)\n", $usesr_total_time, 100*$usesr_total_time / $total_time );
+
+ foreach $key ( keys %g_TimingBlocks )
+ {
+ print sprintf( "$key time: %0.4f sec, (%0.2f%%)\n", $g_TimingBlocks{$key}, 100*$g_TimingBlocks{$key} / $total_time );
+ }
+
+ print sprintf( "Total time : %0.4f sec\n", $total_time );
+}
+