Jørgen P. Tjernø b5dc4a8543 Line-ending fixes for most of the remaining files.
Fixes line-endings for files with extensions vcd, cc, txt, bat, fxc, inc, lst,
proto, mak, mm, cfg, res, rc, def, vmt, vsh, vbsp, inl, asm, m4, vcproj,
vcxproj, sln, in, java, la, manifest, am, and rad.

Also fixes README, CONTRIBUTING, CONTRIBUTORS, LICENSE, CHANGES, COPYING, and
gitignore.

Finally, fixes executable bits.
2013-12-03 11:57:22 -08:00

1394 lines
35 KiB
GLSL

;------------------------------------
; RULES FOR AUTHORING VERTEX SHADERS:
;------------------------------------
; - never use "def" . . .set constants in code instead. . our constant shadowing will break otherwise.
; (same goes for pixel shaders)
; - use cN notation instead of c[N] notation. .makes grepping for registers easier.
; The only exception is c[a0.x+blah] where you have no choice.
$g_NumRegisters = 12;
; NOTE: These must match the same values in vsh_prep.pl!
$vPos = "v0";
$vBoneWeights = "v1";
$vBoneIndices = "v2";
$vNormal = "v3";
$vColor = "v5";
$vSpecular = "v6";
$vTexCoord0 = "v7";
$vTexCoord1 = "v8";
$vTexCoord2 = "v9";
$vTexCoord3 = "v10";
$vTangentS = "v11";
$vTangentT = "v12";
$vUserData = "v14";
if( $g_dx9 )
{
if( $g_usesPos )
{
dcl_position $vPos;
}
if( $g_usesBoneWeights )
{
dcl_blendweight $vBoneWeights;
}
if( $g_usesBoneIndices )
{
dcl_blendindices $vBoneIndices;
}
if( $g_usesNormal )
{
dcl_normal $vNormal;
}
if( $g_usesColor )
{
dcl_color0 $vColor;
}
if( $g_usesSpecular )
{
dcl_color1 $vSpecular;
}
if( $g_usesTexCoord0 )
{
dcl_texcoord0 $vTexCoord0;
}
if( $g_usesTexCoord1 )
{
dcl_texcoord1 $vTexCoord1;
}
if( $g_usesTexCoord2 )
{
dcl_texcoord2 $vTexCoord2;
}
if( $g_usesTexCoord3 )
{
dcl_texcoord3 $vTexCoord3;
}
if( $g_usesTangentS )
{
dcl_tangent $vTangentS;
}
if( $g_usesTangentT )
{
dcl_binormal0 $vTangentT;
}
if( $g_usesUserData )
{
dcl_tangent $vUserData;
}
}
# NOTE: These should match g_LightCombinations in vertexshaderdx8.cpp!
# NOTE: Leave this on single lines or shit might blow up.
@g_staticLightTypeArray = ( "none", "static", "none", "none", "none", "none", "none", "none", "none", "none", "none", "none", "static", "static", "static", "static", "static", "static", "static", "static", "static", "static" );
@g_ambientLightTypeArray = ( "none", "none", "ambient", "ambient", "ambient", "ambient", "ambient", "ambient", "ambient", "ambient", "ambient", "ambient", "ambient", "ambient", "ambient", "ambient", "ambient", "ambient", "ambient", "ambient", "ambient", "ambient" );
@g_localLightType1Array = ( "none", "none", "none", "spot", "point", "directional", "spot", "spot", "spot", "point", "point", "directional", "none", "spot", "point", "directional", "spot", "spot", "spot", "point", "point", "directional" );
@g_localLightType2Array = ( "none", "none", "none", "none", "none", "none", "spot", "point", "directional", "point", "directional", "directional", "none", "none", "none", "none", "spot", "point", "directional", "point", "directional", "directional" );
$cConstants0 = "c0";
$cZero = "c0.x";
$cOne = "c0.y";
$cTwo = "c0.z";
$cHalf = "c0.w";
$cConstants1 = "c1";
$cOOGamma = "c1.x"; # 1/2.2
$cOtherOverbrightFactor = "c1.y"; # overbright
$cOneThird = "c1.z"; # 1/3
$cOverbrightFactor = "c1.w"; # 1/overbright
$cEyePos = "c2";
$cWaterZ = "c2.w";
$cEyePosWaterZ = "c2";
$cLightIndex = "c3";
$cLight0Offset = "c3.x"; # 27
$cLight1Offset = "c3.y"; # 32
$cColorToIntScale = "c3.z"; # matrix array offset = 3.0f * 255.0f + 0.01 (epsilon ensures floor yields desired result)
$cModel0Index = "c3.w"; # base for start of skinning matrices
; NOTE: These must match the same values in vsh_prep.pl!
$cModelViewProj0 = "c4";
$cModelViewProj1 = "c5";
$cModelViewProj2 = "c6";
$cModelViewProj3 = "c7";
$cViewProj0 = "c8";
$cViewProj1 = "c9";
$cViewProj2 = "c10";
$cViewProj3 = "c11";
; currently unused
; c12, c13
$SHADER_SPECIFIC_CONST_10 = "c14";
$SHADER_SPECIFIC_CONST_11 = "c15";
$cFogParams = "c16";
$cFogEndOverFogRange = "c16.x";
$cFogOne = "c16.y";
$cFogMaxDensity = "c16.z";
$cOOFogRange = "c16.w"; # (1/(fogEnd-fogStart))
$cViewModel0 = "c17";
$cViewModel1 = "c18";
$cViewModel2 = "c19";
$cViewModel3 = "c20";
$cAmbientColorPosX = "c21";
$cAmbientColorNegX = "c22";
$cAmbientColorPosY = "c23";
$cAmbientColorNegY = "c24";
$cAmbientColorPosZ = "c25";
$cAmbientColorNegZ = "c26";
$cAmbientColorPosXOffset = "21";
$cAmbientColorPosYOffset = "23";
$cAmbientColorPosZOffset = "25";
$cLight0DiffColor = "c27";
$cLight0Dir = "c28";
$cLight0Pos = "c29";
$cLight0SpotParams = "c30"; # [ exponent, stopdot, stopdot2, 1 / (stopdot - stopdot2)
$cLight0Atten = "c31"; # [ constant, linear, quadratic, 0.0f ]
$cLight1DiffColor = "c32";
$cLight1Dir = "c33";
$cLight1Pos = "c34";
$cLight1SpotParams = "c35"; # [ exponent, stopdot, stopdot2, 1 / (stopdot - stopdot2)
$cLight1Atten = "c36"; # [ constant, linear, quadratic, 0.0f ]
$cModulationColor = "c37";
$SHADER_SPECIFIC_CONST_0 = "c38";
$SHADER_SPECIFIC_CONST_1 = "c39";
$SHADER_SPECIFIC_CONST_2 = "c40";
$SHADER_SPECIFIC_CONST_3 = "c41";
$SHADER_SPECIFIC_CONST_4 = "c42";
$SHADER_SPECIFIC_CONST_5 = "c43";
$SHADER_SPECIFIC_CONST_6 = "c44";
$SHADER_SPECIFIC_CONST_7 = "c45";
$SHADER_SPECIFIC_CONST_8 = "c46";
$SHADER_SPECIFIC_CONST_9 = "c47";
; $SHADER_SPECIFIC_CONST_10 is c14
; $SHADER_SPECIFIC_CONST_11 is c15
; There are 16 model matrices for skinning
; NOTE: These must match the same values in vsh_prep.pl!
$cModel0 = "c48";
$cModel1 = "c49";
$cModel2 = "c50";
sub OutputUsedRegisters
{
local( $i );
; USED REGISTERS
for( $i = 0; $i < $g_NumRegisters; $i++ )
{
if( $g_allocated[$i] )
{
; $g_allocatedname[$i] = r$i
}
}
;
}
sub AllocateRegister
{
local( *reg ) = shift;
local( $regname ) = shift;
local( $i );
for( $i = 0; $i < $g_NumRegisters; $i++ )
{
if( !$g_allocated[$i] )
{
$g_allocated[$i] = 1;
$g_allocatedname[$i] = $regname;
; AllocateRegister $regname = r$i
$reg = "r$i";
&OutputUsedRegisters();
return;
}
}
; Out of registers allocating $regname!
$reg = "rERROR_OUT_OF_REGISTERS";
&OutputUsedRegisters();
}
; pass in a reference to a var that contains a register. . ie \$var where var will constain "r1", etc
sub FreeRegister
{
local( *reg ) = shift;
local( $regname ) = shift;
; FreeRegister $regname = $reg
if( $reg =~ m/rERROR_DEALLOCATED/ )
{
; $regname already deallocated
; $reg = "rALREADY_DEALLOCATED";
&OutputUsedRegisters();
return;
}
; if( $regname ne g_allocatedname[$reg] )
; {
; ; Error freeing $reg
; mov compileerror, freed unallocated register $regname
; }
if( ( $reg =~ m/r(.*)/ ) )
{
$g_allocated[$1] = 0;
}
$reg = "rERROR_DEALLOCATED";
&OutputUsedRegisters();
}
sub CheckUnfreedRegisters()
{
local( $i );
for( $i = 0; $i < $g_NumRegisters; $i++ )
{
if( $g_allocated[$i] )
{
print "ERROR: r$i allocated to $g_allocatedname[$i] at end of program\n";
$g_allocated[$i] = 0;
}
}
}
sub Normalize
{
local( $r ) = shift;
dp3 $r.w, $r, $r
rsq $r.w, $r.w
mul $r, $r, $r.w
}
sub Cross
{
local( $result ) = shift;
local( $a ) = shift;
local( $b ) = shift;
mul $result.xyz, $a.yzx, $b.zxy
mad $result.xyz, -$b.yzx, $a.zxy, $result
}
sub RangeFog
{
local( $projPos ) = shift;
;------------------------------
; Regular range fog
;------------------------------
; oFog.x = 1.0f = no fog
; oFog.x = 0.0f = full fog
; compute fog factor f = (fog_end - dist)*(1/(fog_end-fog_start))
; this is == to: (fog_end/(fog_end-fog_start) - dist/(fog_end-fog_start)
; which can be expressed with a single mad instruction!
; Compute |projPos|
local( $tmp );
&AllocateRegister( \$tmp );
dp3 $tmp.x, $projPos.xyw, $projPos.xyw
rsq $tmp.x, $tmp.x
rcp $tmp.x, $tmp.x
if( $g_dx9 )
{
mad $tmp, -$tmp.x, $cOOFogRange, $cFogEndOverFogRange
min $tmp, $tmp, $cOne
max oFog, $tmp.x, $cFogMaxDensity
}
else
{
mad $tmp, -$tmp.x, $cOOFogRange, $cFogEndOverFogRange
min $tmp, $tmp, $cOne
max oFog.x, $tmp.x, $cFogMaxDensity
}
&FreeRegister( \$tmp );
}
sub DepthFog
{
local( $projPos ) = shift;
local( $dest ) = shift;
if ( $dest eq "" )
{
$dest = "oFog";
}
;------------------------------
; Regular range fog
;------------------------------
; oFog.x = 1.0f = no fog
; oFog.x = 0.0f = full fog
; compute fog factor f = (fog_end - dist)*(1/(fog_end-fog_start))
; this is == to: (fog_end/(fog_end-fog_start) - dist/(fog_end-fog_start)
; which can be expressed with a single mad instruction!
; Compute |projPos|
local( $tmp );
&AllocateRegister( \$tmp );
if( $g_dx9 )
{
mad $tmp, -$projPos.w, $cOOFogRange, $cFogEndOverFogRange
min $tmp, $tmp, $cOne
max $dest, $tmp.x, $cFogMaxDensity
}
else
{
mad $tmp, -$projPos.w, $cOOFogRange, $cFogEndOverFogRange
min $tmp, $tmp, $cOne
max $dest.x, $tmp.x, $cFogMaxDensity
}
&FreeRegister( \$tmp );
}
sub WaterRangeFog
{
; oFog.x = 1.0f = no fog
; oFog.x = 0.0f = full fog
; only $worldPos.z is used out of worldPos
local( $worldPos ) = shift;
local( $projPos ) = shift;
local( $tmp );
&AllocateRegister( \$tmp );
; This is simple similar triangles. Imagine a line passing from the point directly vertically
; and another line passing from the point to the eye position.
; Let d = total distance from point to the eye
; Let h = vertical distance from the point to the eye
; Let hw = vertical distance from the point to the water surface
; Let dw = distance from the point to a point on the water surface that lies along the ray from point to eye
; Therefore d/h = dw/hw by similar triangles, or dw = d * hw / h.
; d = |projPos|, h = eyepos.z - worldPos.z, hw = waterheight.z - worldPos.z, dw = what we solve for
; Now, tmp.x = hw, and tmp.y = h
add $tmp.xy, $cEyePosWaterZ.wz, -$worldPos.z
; if $tmp.x < 0, then set it to 0
; This is the equivalent of moving the vert to the water surface if it's above the water surface
max $tmp.x, $tmp.x, $cZero
; Compute 1 / |projPos| = 1/d
dp3 $tmp.z, $projPos.xyw, $projPos.xyw
rsq $tmp.z, $tmp.z
; Now we have h/d
mul $tmp.z, $tmp.z, $tmp.y
; Now we have d/h
rcp $tmp.w, $tmp.z
; We finally have d * hw / h
; $tmp.w is now the distance that we see through water.
mul $tmp.w, $tmp.x, $tmp.w
if( $g_dx9 )
{
mad $tmp, -$tmp.w, $cOOFogRange, $cFogOne
min $tmp, $tmp, $cOne
max oFog, $tmp.x, $cFogMaxDensity
}
else
{
mad $tmp, -$tmp.w, $cOOFogRange, $cFogOne
min $tmp, $tmp, $cOne
max oFog.x, $tmp.x, $cFogMaxDensity
}
&FreeRegister( \$tmp );
}
sub WaterDepthFog
{
; oFog.x = 1.0f = no fog
; oFog.x = 0.0f = full fog
; only $worldPos.z is used out of worldPos
local( $worldPos ) = shift;
local( $projPos ) = shift;
local( $dest ) = shift;
if ( $dest eq "" )
{
$dest = "oFog";
}
local( $tmp );
&AllocateRegister( \$tmp );
; This is simple similar triangles. Imagine a line passing from the point directly vertically
; and another line passing from the point to the eye position.
; Let d = total distance from point to the eye
; Let h = vertical distance from the point to the eye
; Let hw = vertical distance from the point to the water surface
; Let dw = distance from the point to a point on the water surface that lies along the ray from point to eye
; Therefore d/h = dw/hw by similar triangles, or dw = d * hw / h.
; d = projPos.w, h = eyepos.z - worldPos.z, hw = waterheight.z - worldPos.z, dw = what we solve for
; Now, tmp.x = hw, and tmp.y = h
add $tmp.xy, $cEyePosWaterZ.wz, -$worldPos.z
; if $tmp.x < 0, then set it to 0
; This is the equivalent of moving the vert to the water surface if it's above the water surface
max $tmp.x, $tmp.x, $cZero
; Now we have 1/h
rcp $tmp.z, $tmp.y
; Now we have d/h
mul $tmp.w, $projPos.w, $tmp.z
; We finally have d * hw / h
; $tmp.w is now the distance that we see through water.
mul $tmp.w, $tmp.x, $tmp.w
if( $g_dx9 )
{
mad $tmp, -$tmp.w, $cOOFogRange, $cFogOne
min $tmp, $tmp, $cOne
max $dest, $tmp.x, $cZero
}
else
{
mad $tmp, -$tmp.w, $cOOFogRange, $cFogOne
min $tmp, $tmp, $cOne
max $dest.x, $tmp.x, $cZero
}
&FreeRegister( \$tmp );
}
;------------------------------------------------------------------------------
; Main fogging routine
;------------------------------------------------------------------------------
sub CalcFog
{
if( !defined $DOWATERFOG )
{
die "CalcFog called without using \$DOWATERFOG\n";
}
my $fogType;
if( $DOWATERFOG == 0 )
{
$fogType = "rangefog";
}
else
{
$fogType = "heightfog";
}
# print "\$fogType = $fogType\n";
; CalcFog
local( $worldPos ) = shift;
local( $projPos ) = shift;
local( $dest ) = shift;
if ( $dest eq "" )
{
$dest = "oFog";
}
if( $fogType eq "rangefog" )
{
&DepthFog( $projPos, $dest );
}
elsif( $fogType eq "heightfog" )
{
&WaterDepthFog( $worldPos, $projPos, $dest );
}
else
{
die;
}
}
sub CalcRangeFog
{
; CalcFog
local( $worldPos ) = shift;
local( $projPos ) = shift;
if( $DOWATERFOG == 0 )
{
&RangeFog( $projPos );
}
elsif( $DOWATERFOG == 1 )
{
&WaterRangeFog( $worldPos, $projPos );
}
else
{
die;
}
}
sub GammaToLinear
{
local( $gamma ) = shift;
local( $linear ) = shift;
local( $tmp );
&AllocateRegister( \$tmp );
; Is rcp more expensive than just storing 2.2 somewhere and doing a mov?
rcp $gamma.w, $cOOGamma ; $gamma.w = 2.2
lit $linear.z, $gamma.zzzw ; r0.z = linear blue
lit $tmp.z, $gamma.yyyw ; r2.z = linear green
mov $linear.y, $tmp.z ; r0.y = linear green
lit $tmp.z, $gamma.xxxw ; r2.z = linear red
mov $linear.x, $tmp.z ; r0.x = linear red
&FreeRegister( \$tmp );
}
sub LinearToGamma
{
local( $linear ) = shift;
local( $gamma ) = shift;
local( $tmp );
&AllocateRegister( \$tmp );
mov $linear.w, $cOOGamma ; $linear.w = 1.0/2.2
lit $gamma.z, $linear.zzzw ; r0.z = gamma blue
lit $tmp.z, $linear.yyyw ; r2.z = gamma green
mov $gamma.y, $tmp.z ; r0.y = gamma green
lit $tmp.z, $linear.xxxw ; r2.z = gamma red
mov $gamma.x, $tmp.z ; r0.x = gamma red
&FreeRegister( \$tmp );
}
sub ComputeReflectionVector
{
local( $worldPos ) = shift;
local( $worldNormal ) = shift;
local( $reflectionVector ) = shift;
local( $vertToEye ); &AllocateRegister( \$vertToEye );
local( $tmp ); &AllocateRegister( \$tmp );
; compute reflection vector r = 2 * (n dot v) n - v
sub $vertToEye.xyz, $cEyePos.xyz, $worldPos ; $tmp1 = v = c - p
dp3 $tmp, $worldNormal, $vertToEye ; $tmp = n dot v
mul $tmp.xyz, $tmp.xyz, $worldNormal ; $tmp = (n dot v ) n
mad $reflectionVector.xyz, $tmp, $cTwo, -$vertToEye
&FreeRegister( \$vertToEye );
&FreeRegister( \$tmp );
}
sub ComputeSphereMapTexCoords
{
local( $reflectionVector ) = shift;
local( $sphereMapTexCoords ) = shift;
local( $tmp ); &AllocateRegister( \$tmp );
; transform reflection vector into view space
dp3 $tmp.x, $reflectionVector, $cViewModel0
dp3 $tmp.y, $reflectionVector, $cViewModel1
dp3 $tmp.z, $reflectionVector, $cViewModel2
; generate <rx ry rz+1>
add $tmp.z, $tmp.z, $cOne
; find 1 / the length of r2
dp3 $tmp.w, $tmp, $tmp
rsq $tmp.w, $tmp.w
; r1 = r2/|r2| + 1
mad $tmp.xy, $tmp.w, $tmp, $cOne
mul $sphereMapTexCoords.xy, $tmp.xy, $cHalf
&FreeRegister( \$tmp );
}
sub SkinPosition
{
# print "\$SKINNING = $SKINNING\n";
local( $worldPos ) = shift;
if( !defined $SKINNING )
{
die "using \$SKINNING without defining.\n";
}
if( $SKINNING == 0 )
{
;
; 0 bone skinning (4 instructions)
;
; Transform position into world space
; position
dp4 $worldPos.x, $vPos, $cModel0
dp4 $worldPos.y, $vPos, $cModel1
dp4 $worldPos.z, $vPos, $cModel2
mov $worldPos.w, $cOne
}
else
{
;
; 3 bone skinning (19 instructions)
;
local( $boneIndices );
local( $blendedMatrix0 );
local( $blendedMatrix1 );
local( $blendedMatrix2 );
local( $localPos );
&AllocateRegister( \$boneIndices );
&AllocateRegister( \$blendedMatrix0 );
&AllocateRegister( \$blendedMatrix1 );
&AllocateRegister( \$blendedMatrix2 );
; Transform position into world space using all bones
; denormalize d3dcolor to matrix index
mad $boneIndices, $vBoneIndices, $cColorToIntScale, $cModel0Index
if ( $g_x360 )
{
mov $boneIndices, $boneIndices.zyxw
}
; r11 = boneindices at this point
; first matrix
mov a0.x, $boneIndices.z
mul $blendedMatrix0, $vBoneWeights.x, c[a0.x]
mul $blendedMatrix1, $vBoneWeights.x, c[a0.x+1]
mul $blendedMatrix2, $vBoneWeights.x, c[a0.x+2]
; second matrix
mov a0.x, $boneIndices.y
mad $blendedMatrix0, $vBoneWeights.y, c[a0.x], $blendedMatrix0
mad $blendedMatrix1, $vBoneWeights.y, c[a0.x+1], $blendedMatrix1
mad $blendedMatrix2, $vBoneWeights.y, c[a0.x+2], $blendedMatrix2
; Calculate third weight
; compute 1-(weight1+weight2) to calculate weight2
; Use $boneIndices.w as a temp since we aren't using it for anything.
add $boneIndices.w, $vBoneWeights.x, $vBoneWeights.y
sub $boneIndices.w, $cOne, $boneIndices.w
; third matrix
mov a0.x, $boneIndices.x
mad $blendedMatrix0, $boneIndices.w, c[a0.x], $blendedMatrix0
mad $blendedMatrix1, $boneIndices.w, c[a0.x+1], $blendedMatrix1
mad $blendedMatrix2, $boneIndices.w, c[a0.x+2], $blendedMatrix2
dp4 $worldPos.x, $vPos, $blendedMatrix0
dp4 $worldPos.y, $vPos, $blendedMatrix1
dp4 $worldPos.z, $vPos, $blendedMatrix2
mov $worldPos.w, $cOne
&FreeRegister( \$boneIndices );
&FreeRegister( \$blendedMatrix0 );
&FreeRegister( \$blendedMatrix1 );
&FreeRegister( \$blendedMatrix2 );
}
}
sub SkinPositionAndNormal
{
# print "\$SKINNING = $SKINNING\n";
local( $worldPos ) = shift;
local( $worldNormal ) = shift;
if( !defined $SKINNING )
{
die "using \$SKINNING without defining.\n";
}
if( $SKINNING == 0 )
{
;
; 0 bone skinning (13 instructions)
;
; Transform position + normal + tangentS + tangentT into world space
; position
dp4 $worldPos.x, $vPos, $cModel0
dp4 $worldPos.y, $vPos, $cModel1
dp4 $worldPos.z, $vPos, $cModel2
mov $worldPos.w, $cOne
; normal
dp3 $worldNormal.x, $vNormal, $cModel0
dp3 $worldNormal.y, $vNormal, $cModel1
dp3 $worldNormal.z, $vNormal, $cModel2
}
else
{
local( $boneIndices );
local( $blendedMatrix0 );
local( $blendedMatrix1 );
local( $blendedMatrix2 );
local( $localPos );
local( $localNormal );
local( $normalLength );
local( $ooNormalLength );
&AllocateRegister( \$boneIndices );
&AllocateRegister( \$blendedMatrix0 );
&AllocateRegister( \$blendedMatrix1 );
&AllocateRegister( \$blendedMatrix2 );
; Transform position into world space using all bones
; denormalize d3dcolor to matrix index
mad $boneIndices, $vBoneIndices, $cColorToIntScale, $cModel0Index
if ( $g_x360 )
{
mov $boneIndices, $boneIndices.zyxw
}
; r11 = boneindices at this point
; first matrix
mov a0.x, $boneIndices.z
mul $blendedMatrix0, $vBoneWeights.x, c[a0.x]
mul $blendedMatrix1, $vBoneWeights.x, c[a0.x+1]
mul $blendedMatrix2, $vBoneWeights.x, c[a0.x+2]
; second matrix
mov a0.x, $boneIndices.y
mad $blendedMatrix0, $vBoneWeights.y, c[a0.x], $blendedMatrix0
mad $blendedMatrix1, $vBoneWeights.y, c[a0.x+1], $blendedMatrix1
mad $blendedMatrix2, $vBoneWeights.y, c[a0.x+2], $blendedMatrix2
; Calculate third weight
; compute 1-(weight1+weight2) to calculate weight2
; Use $boneIndices.w as a temp since we aren't using it for anything.
add $boneIndices.w, $vBoneWeights.x, $vBoneWeights.y
sub $boneIndices.w, $cOne, $boneIndices.w
; third matrix
mov a0.x, $boneIndices.x
mad $blendedMatrix0, $boneIndices.w, c[a0.x], $blendedMatrix0
mad $blendedMatrix1, $boneIndices.w, c[a0.x+1], $blendedMatrix1
mad $blendedMatrix2, $boneIndices.w, c[a0.x+2], $blendedMatrix2
dp4 $worldPos.x, $vPos, $blendedMatrix0
dp4 $worldPos.y, $vPos, $blendedMatrix1
dp4 $worldPos.z, $vPos, $blendedMatrix2
mov $worldPos.w, $cOne
; normal
dp3 $worldNormal.x, $vNormal, $blendedMatrix0
dp3 $worldNormal.y, $vNormal, $blendedMatrix1
dp3 $worldNormal.z, $vNormal, $blendedMatrix2
&FreeRegister( \$boneIndices );
&FreeRegister( \$blendedMatrix0 );
&FreeRegister( \$blendedMatrix1 );
&FreeRegister( \$blendedMatrix2 );
}
}
sub SkinPositionNormalAndTangentSpace
{
# print "\$SKINNING = $SKINNING\n";
local( $worldPos ) = shift;
local( $worldNormal ) = shift;
local( $worldTangentS ) = shift;
local( $worldTangentT ) = shift;
local( $userData );
local( $localPos );
local( $localNormal );
local( $normalLength );
local( $ooNormalLength );
if( !defined $SKINNING )
{
die "using \$SKINNING without defining.\n";
}
# X360TBD: needed for compressed vertex format
# if ( $g_x360 )
# {
# &AllocateRegister( \$userData );
# ; remap compressed range [0..1] to [-1..1]
# mad $userData, $vUserData, $cTwo, -$cOne
# }
if( $SKINNING == 0 )
{
;
; 0 bone skinning (13 instructions)
;
; Transform position + normal + tangentS + tangentT into world space
dp4 $worldPos.x, $vPos, $cModel0
dp4 $worldPos.y, $vPos, $cModel1
dp4 $worldPos.z, $vPos, $cModel2
mov $worldPos.w, $cOne
; normal
dp3 $worldNormal.x, $vNormal, $cModel0
dp3 $worldNormal.y, $vNormal, $cModel1
dp3 $worldNormal.z, $vNormal, $cModel2
# X360TBD: needed for compressed vertex format
# if ( $g_x360 )
# {
# ; tangents
# dp3 $worldTangentS.x, $userData, $cModel0
# dp3 $worldTangentS.y, $userData, $cModel1
# dp3 $worldTangentS.z, $userData, $cModel2
#
# ; calculate tangent t via cross( N, S ) * S[3]
# &Cross( $worldTangentT, $worldNormal, $worldTangentS );
# mul $worldTangentT.xyz, $userData.w, $worldTangentT.xyz
# }
# else
{
; tangents
dp3 $worldTangentS.x, $vUserData, $cModel0
dp3 $worldTangentS.y, $vUserData, $cModel1
dp3 $worldTangentS.z, $vUserData, $cModel2
; calculate tangent t via cross( N, S ) * S[3]
&Cross( $worldTangentT, $worldNormal, $worldTangentS );
mul $worldTangentT.xyz, $vUserData.w, $worldTangentT.xyz
}
}
else
{
local( $boneIndices );
local( $blendedMatrix0 );
local( $blendedMatrix1 );
local( $blendedMatrix2 );
&AllocateRegister( \$boneIndices );
&AllocateRegister( \$blendedMatrix0 );
&AllocateRegister( \$blendedMatrix1 );
&AllocateRegister( \$blendedMatrix2 );
; Transform position into world space using all bones
; denormalize d3dcolor to matrix index
mad $boneIndices, $vBoneIndices, $cColorToIntScale, $cModel0Index
if ( $g_x360 )
{
mov $boneIndices, $boneIndices.zyxw
}
; r11 = boneindices at this point
; first matrix
mov a0.x, $boneIndices.z
mul $blendedMatrix0, $vBoneWeights.x, c[a0.x]
mul $blendedMatrix1, $vBoneWeights.x, c[a0.x+1]
mul $blendedMatrix2, $vBoneWeights.x, c[a0.x+2]
; second matrix
mov a0.x, $boneIndices.y
mad $blendedMatrix0, $vBoneWeights.y, c[a0.x], $blendedMatrix0
mad $blendedMatrix1, $vBoneWeights.y, c[a0.x+1], $blendedMatrix1
mad $blendedMatrix2, $vBoneWeights.y, c[a0.x+2], $blendedMatrix2
; Calculate third weight
; compute 1-(weight1+weight2) to calculate weight2
; Use $boneIndices.w as a temp since we aren't using it for anything.
add $boneIndices.w, $vBoneWeights.x, $vBoneWeights.y
sub $boneIndices.w, $cOne, $boneIndices.w
; third matrix
mov a0.x, $boneIndices.x
mad $blendedMatrix0, $boneIndices.w, c[a0.x], $blendedMatrix0
mad $blendedMatrix1, $boneIndices.w, c[a0.x+1], $blendedMatrix1
mad $blendedMatrix2, $boneIndices.w, c[a0.x+2], $blendedMatrix2
; position
dp4 $worldPos.x, $vPos, $blendedMatrix0
dp4 $worldPos.y, $vPos, $blendedMatrix1
dp4 $worldPos.z, $vPos, $blendedMatrix2
mov $worldPos.w, $cOne
; normal
dp3 $worldNormal.x, $vNormal, $blendedMatrix0
dp3 $worldNormal.y, $vNormal, $blendedMatrix1
dp3 $worldNormal.z, $vNormal, $blendedMatrix2
# X360TBD: needed for compressed vertex format
# if ( $g_x360 )
# {
# ; tangents
# dp3 $worldTangentS.x, $userData, $blendedMatrix0
# dp3 $worldTangentS.y, $userData, $blendedMatrix1
# dp3 $worldTangentS.z, $userData, $blendedMatrix2
#
# ; calculate tangent t via cross( N, S ) * S[3]
# &Cross( $worldTangentT, $worldNormal, $worldTangentS );
# mul $worldTangentT.xyz, $userData.w, $worldTangentT.xyz
# }
# else
{
; tangents
dp3 $worldTangentS.x, $vUserData, $blendedMatrix0
dp3 $worldTangentS.y, $vUserData, $blendedMatrix1
dp3 $worldTangentS.z, $vUserData, $blendedMatrix2
; calculate tangent t via cross( N, S ) * S[3]
&Cross( $worldTangentT, $worldNormal, $worldTangentS );
mul $worldTangentT.xyz, $vUserData.w, $worldTangentT.xyz
}
&FreeRegister( \$boneIndices );
&FreeRegister( \$blendedMatrix0 );
&FreeRegister( \$blendedMatrix1 );
&FreeRegister( \$blendedMatrix2 );
}
# X360TBD: needed for compressed vertex format
# if ( $g_x360 )
# {
# &FreeRegister( \$userData );
# }
}
sub ColorClamp
{
; ColorClamp; stomps $color.w
local( $color ) = shift;
local( $dst ) = shift;
; Get the max of RGB and stick it in W
max $color.w, $color.x, $color.y
max $color.w, $color.w, $color.z
; get the greater of one and the max color.
max $color.w, $color.w, $cOne
rcp $color.w, $color.w
mul $dst.xyz, $color.w, $color.xyz
}
sub AmbientLight
{
local( $worldNormal ) = shift;
local( $linearColor ) = shift;
local( $add ) = shift;
; Ambient lighting
&AllocateRegister( \$nSquared );
&AllocateRegister( \$isNegative );
mul $nSquared.xyz, $worldNormal.xyz, $worldNormal.xyz ; compute n times n
slt $isNegative.xyz, $worldNormal.xyz, $cZero ; Figure out whether each component is >0
mov a0.x, $isNegative.x
if( $add )
{
mad $linearColor.xyz, $nSquared.x, c[a0.x + $cAmbientColorPosXOffset], $linearColor ; $linearColor = normal[0]*normal[0] * box color of appropriate x side
}
else
{
mul $linearColor.xyz, $nSquared.x, c[a0.x + $cAmbientColorPosXOffset] ; $linearColor = normal[0]*normal[0] * box color of appropriate x side
}
mov a0.x, $isNegative.y
mad $linearColor.xyz, $nSquared.y, c[a0.x + $cAmbientColorPosYOffset], $linearColor
mov a0.x, $isNegative.z
mad $linearColor.xyz, $nSquared.z, c[a0.x + $cAmbientColorPosZOffset], $linearColor
&FreeRegister( \$isNegative );
&FreeRegister( \$nSquared );
}
sub DirectionalLight
{
local( $worldNormal ) = shift;
local( $linearColor ) = shift;
local( $add ) = shift;
&AllocateRegister( \$nDotL ); # FIXME: This only needs to be a scalar
; NOTE: Gotta use -l here, since light direction = -l
; DIRECTIONAL LIGHT
; compute n dot l
dp3 $nDotL.x, -c[a0.x + 1], $worldNormal
if ( $HALF_LAMBERT == 0 )
{
; lambert
max $nDotL.x, $nDotL.x, c0.x ; Clamp to zero
}
elsif ( $HALF_LAMBERT == 1 )
{
; half-lambert
mad $nDotL.x, $nDotL.x, $cHalf, $cHalf ; dot = (dot * 0.5 + 0.5)^2
mul $nDotL.x, $nDotL.x, $nDotL.x
}
else
{
die "\$HALF_LAMBERT is hosed\n";
}
if( $add )
{
mad $linearColor.xyz, c[a0.x], $nDotL.x, $linearColor
}
else
{
mul $linearColor.xyz, c[a0.x], $nDotL.x
}
&FreeRegister( \$nDotL );
}
sub PointLight
{
local( $worldPos ) = shift;
local( $worldNormal ) = shift;
local( $linearColor ) = shift;
local( $add ) = shift;
local( $lightDir );
&AllocateRegister( \$lightDir );
; POINT LIGHT
; compute light direction
sub $lightDir, c[a0.x+2], $worldPos
local( $lightDistSquared );
local( $ooLightDist );
&AllocateRegister( \$lightDistSquared );
&AllocateRegister( \$ooLightDist );
; normalize light direction, maintain temporaries for attenuation
dp3 $lightDistSquared, $lightDir, $lightDir
rsq $ooLightDist, $lightDistSquared.x
mul $lightDir, $lightDir, $ooLightDist.x
local( $attenuationFactors );
&AllocateRegister( \$attenuationFactors );
; compute attenuation amount (r2 = 'd*d d*d d*d d*d', r3 = '1/d 1/d 1/d 1/d')
dst $attenuationFactors, $lightDistSquared, $ooLightDist ; r4 = ( 1, d, d*d, 1/d )
&FreeRegister( \$lightDistSquared );
&FreeRegister( \$ooLightDist );
local( $attenuation );
&AllocateRegister( \$attenuation );
dp3 $attenuation, $attenuationFactors, c[a0.x+4] ; r3 = atten0 + d * atten1 + d*d * atten2
rcp $lightDir.w, $attenuation ; $lightDir.w = 1 / (atten0 + d * atten1 + d*d * atten2)
&FreeRegister( \$attenuationFactors );
&FreeRegister( \$attenuation );
local( $tmp );
&AllocateRegister( \$tmp ); # FIXME : really only needs to be a scalar
; compute n dot l, fold in distance attenutation
dp3 $tmp.x, $lightDir, $worldNormal
if ( $HALF_LAMBERT == 0 )
{
; lambert
max $tmp.x, $tmp.x, c0.x ; Clamp to zero
}
elsif ( $HALF_LAMBERT == 1 )
{
; half-lambert
mad $tmp.x, $tmp.x, $cHalf, $cHalf ; dot = (dot * 0.5 + 0.5)^2
mul $tmp.x, $tmp.x, $tmp.x
}
else
{
die "\$HALF_LAMBERT is hosed\n";
}
mul $tmp.x, $tmp.x, $lightDir.w
if( $add )
{
mad $linearColor.xyz, c[a0.x], $tmp.x, $linearColor
}
else
{
mul $linearColor.xyz, c[a0.x], $tmp.x
}
&FreeRegister( \$lightDir );
&FreeRegister( \$tmp ); # FIXME : really only needs to be a scalar
}
sub SpotLight
{
local( $worldPos ) = shift;
local( $worldNormal ) = shift;
local( $linearColor ) = shift;
local( $add ) = shift;
local( $lightDir );
&AllocateRegister( \$lightDir );
; SPOTLIGHT
; compute light direction
sub $lightDir, c[a0.x+2], $worldPos
local( $lightDistSquared );
local( $ooLightDist );
&AllocateRegister( \$lightDistSquared );
&AllocateRegister( \$ooLightDist );
; normalize light direction, maintain temporaries for attenuation
dp3 $lightDistSquared, $lightDir, $lightDir
rsq $ooLightDist, $lightDistSquared.x
mul $lightDir, $lightDir, $ooLightDist.x
local( $attenuationFactors );
&AllocateRegister( \$attenuationFactors );
; compute attenuation amount (r2 = 'd*d d*d d*d d*d', r3 = '1/d 1/d 1/d 1/d')
dst $attenuationFactors, $lightDistSquared, $ooLightDist ; r4 = ( 1, d, d*d, 1/d )
&FreeRegister( \$lightDistSquared );
&FreeRegister( \$ooLightDist );
local( $attenuation ); &AllocateRegister( \$attenuation );
dp3 $attenuation, $attenuationFactors, c[a0.x+4] ; r3 = atten0 + d * atten1 + d*d * atten2
rcp $lightDir.w, $attenuation ; r1.w = 1 / (atten0 + d * atten1 + d*d * atten2)
&FreeRegister( \$attenuationFactors );
&FreeRegister( \$attenuation );
local( $litSrc ); &AllocateRegister( \$litSrc );
local( $tmp ); &AllocateRegister( \$tmp ); # FIXME - only needs to be scalar
; compute n dot l
dp3 $litSrc.x, $worldNormal, $lightDir
if ( $HALF_LAMBERT == 0 )
{
; lambert
max $litSrc.x, $litSrc.x, c0.x ; Clamp to zero
}
elsif ( $HALF_LAMBERT == 1 )
{
; half-lambert
mad $litSrc.x, $litSrc.x, $cHalf, $cHalf ; dot = (dot * 0.5 + 0.5) ^ 2
mul $litSrc.x, $litSrc.x, $litSrc.x
}
else
{
die "\$HALF_LAMBERT is hosed\n";
}
; compute angular attenuation
dp3 $tmp.x, c[a0.x+1], -$lightDir ; dot = -delta * spot direction
sub $litSrc.y, $tmp.x, c[a0.x+3].z ; r2.y = dot - stopdot2
&FreeRegister( \$tmp );
mul $litSrc.y, $litSrc.y, c[a0.x+3].w ; r2.y = (dot - stopdot2) / (stopdot - stopdot2)
mov $litSrc.w, c[a0.x+3].x ; r2.w = exponent
local( $litDst ); &AllocateRegister( \$litDst );
lit $litDst, $litSrc ; r3.y = N dot L or 0, whichever is bigger
&FreeRegister( \$litSrc );
; r3.z = pow((dot - stopdot2) / (stopdot - stopdot2), exponent)
min $litDst.z, $litDst.z, $cOne ; clamp pow() to 1
local( $tmp1 ); &AllocateRegister( \$tmp1 );
local( $tmp2 ); &AllocateRegister( \$tmp2 ); # FIXME - could be scalar
; fold in distance attenutation with other factors
mul $tmp1, c[a0.x], $lightDir.w
mul $tmp2.x, $litDst.y, $litDst.z
if( $add )
{
mad $linearColor.xyz, $tmp1, $tmp2.x, $linearColor
}
else
{
mul $linearColor.xyz, $tmp1, $tmp2.x
}
&FreeRegister( \$lightDir );
&FreeRegister( \$litDst );
&FreeRegister( \$tmp1 );
&FreeRegister( \$tmp2 );
}
sub DoLight
{
local( $lightType ) = shift;
local( $worldPos ) = shift;
local( $worldNormal ) = shift;
local( $linearColor ) = shift;
local( $add ) = shift;
if( $lightType eq "spot" )
{
&SpotLight( $worldPos, $worldNormal, $linearColor, $add );
}
elsif( $lightType eq "point" )
{
&PointLight( $worldPos, $worldNormal, $linearColor, $add );
}
elsif( $lightType eq "directional" )
{
&DirectionalLight( $worldNormal, $linearColor, $add );
}
else
{
die "don't know about light type \"$lightType\"\n";
}
}
sub DoLighting
{
if( !defined $LIGHT_COMBO )
{
die "DoLighting called without using \$LIGHT_COMBO\n";
}
if ( !defined $HALF_LAMBERT )
{
die "DoLighting called without using \$HALF_LAMBERT\n";
}
my $staticLightType = $g_staticLightTypeArray[$LIGHT_COMBO];
my $ambientLightType = $g_ambientLightTypeArray[$LIGHT_COMBO];
my $localLightType1 = $g_localLightType1Array[$LIGHT_COMBO];
my $localLightType2 = $g_localLightType2Array[$LIGHT_COMBO];
# print "\$staticLightType = $staticLightType\n";
# print "\$ambientLightType = $ambientLightType\n";
# print "\$localLightType1 = $localLightType1\n";
# print "\$localLightType2 = $localLightType2\n";
local( $worldPos ) = shift;
local( $worldNormal ) = shift;
; special case for no lighting
if( $staticLightType eq "none" && $ambientLightType eq "none" &&
$localLightType1 eq "none" && $localLightType2 eq "none" )
{
; Have to write something here since debug d3d runtime will barf otherwise.
mov oD0, $cOne
return;
}
; special case for static lighting only
; Don't need to bother converting to linear space in this case.
if( $staticLightType eq "static" && $ambientLightType eq "none" &&
$localLightType1 eq "none" && $localLightType2 eq "none" )
{
mov oD0, $vSpecular
return;
}
alloc $linearColor
alloc $gammaColor
local( $add ) = 0;
if( $staticLightType eq "static" )
{
; The static lighting comes in in gamma space and has also been premultiplied by $cOverbrightFactor
; need to get it into
; linear space so that we can do adds.
rcp $gammaColor.w, $cOverbrightFactor
mul $gammaColor.xyz, $vSpecular, $gammaColor.w
&GammaToLinear( $gammaColor, $linearColor );
$add = 1;
}
if( $ambientLightType eq "ambient" )
{
&AmbientLight( $worldNormal, $linearColor, $add );
$add = 1;
}
if( $localLightType1 ne "none" )
{
mov a0.x, $cLight0Offset
&DoLight( $localLightType1, $worldPos, $worldNormal, $linearColor, $add );
$add = 1;
}
if( $localLightType2 ne "none" )
{
mov a0.x, $cLight1Offset
&DoLight( $localLightType2, $worldPos, $worldNormal, $linearColor, $add );
$add = 1;
}
;------------------------------------------------------------------------------
; Output color (gamma correction)
;------------------------------------------------------------------------------
&LinearToGamma( $linearColor, $gammaColor );
if( 0 )
{
mul oD0.xyz, $gammaColor.xyz, $cOverbrightFactor
}
else
{
mul $gammaColor.xyz, $gammaColor.xyz, $cOverbrightFactor
&ColorClamp( $gammaColor, "oD0" );
}
; mov oD0.xyz, $linearColor
mov oD0.w, $cOne ; make sure all components are defined
free $linearColor
free $gammaColor
}
sub DoDynamicLightingToLinear
{
local( $worldPos ) = shift;
local( $worldNormal ) = shift;
local( $linearColor ) = shift;
if( !defined $LIGHT_COMBO )
{
die "DoLighting called without using \$LIGHT_COMBO\n";
}
if ( !defined $HALF_LAMBERT )
{
die "DoLighting called without using \$HALF_LAMBERT\n";
}
my $staticLightType = $g_staticLightTypeArray[$LIGHT_COMBO];
my $ambientLightType = $g_ambientLightTypeArray[$LIGHT_COMBO];
my $localLightType1 = $g_localLightType1Array[$LIGHT_COMBO];
my $localLightType2 = $g_localLightType2Array[$LIGHT_COMBO];
# No lights at all. . note that we don't even consider static lighting here.
if( $ambientLightType eq "none" &&
$localLightType1 eq "none" && $localLightType2 eq "none" )
{
mov $linearColor, $cZero
return;
}
local( $add ) = 0;
if( $ambientLightType eq "ambient" )
{
&AmbientLight( $worldNormal, $linearColor, $add );
$add = 1;
}
if( $localLightType1 ne "none" )
{
mov a0.x, $cLight0Offset
&DoLight( $localLightType1, $worldPos, $worldNormal, $linearColor, $add );
$add = 1;
}
if( $localLightType2 ne "none" )
{
mov a0.x, $cLight1Offset
&DoLight( $localLightType2, $worldPos, $worldNormal, $linearColor, $add );
$add = 1;
}
}
sub NotImplementedYet
{
&AllocateRegister( \$projPos );
dp4 $projPos.x, $worldPos, $cViewProj0
dp4 $projPos.y, $worldPos, $cViewProj1
dp4 $projPos.z, $worldPos, $cViewProj2
dp4 $projPos.w, $worldPos, $cViewProj3
mov oPos, $projPos
&FreeRegister( \$projPos );
exit;
}