mirror of
https://github.com/mapbase-source/source-sdk-2013.git
synced 2025-01-21 11:17:56 +03:00
b5dc4a8543
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.
1394 lines
35 KiB
GLSL
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;
|
|
}
|