You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1106 lines
27 KiB
1106 lines
27 KiB
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 ); |
|
} |
|
|
|
|