//-----------------------------------------------------------------------------
// ps11_AnisoLight.sha
// 
// Uses a dependant texture read to look up a function based on
// the Light dot direction of anisotropy and the Reflection vector dot
// the direction of anisotropy to get a specular highlight and diffuse component
// of brushed metal type lighting on a per pixel basis.
//-----------------------------------------------------------------------------

matrix mWVP;    // World*View*Projection matrix
matrix mWrt;     // Inverse World
matrix mW1;     // Inverse World
vector pOV;     // Object space viewer position
vector pOL;
vector cnst;

texture tAnisoDirection;
texture tGloss;
texture tAniso;

DWord cAmbient = 0x40404040;

vertexshader vAnisoLight = 
	decl
	{
		stream 0;
		float    v0[3];  // Position
		D3DCOLOR v3;     // Normal
		float    v7[2];  // Tex coord 0
		D3DCOLOR v8;     // Binormal
		D3DCOLOR v9;     // Tangent
	}
	asm
	{
        ; Sample vertex shader for per pixel anisotropic lighting 
        ;
        ;        [Lx  Ly  Lz] [Tx]
        ;        [Vx  Vy  Vz]*[Ty]
        ;        [0   0   1]  [Tz]
        ;
        ;   Since Tz is always zero (it's a tangent, after all), we can set it to 1.0 in the direction-of-anisotropy map. 
        ; Also we need a scale by .5 and bias by .5 to get the texture coordinates in the 0 to 1 range. 
        ; So we end up with this operation:
        ;
        ;        [.5Lx  .5Ly  .5]   [Tx]
        ;        [.5Vx  .5Vy  .5] * [Ty]
        ;                           [1]
        ;
        ;        [.5LxTx + .5LyTy + .5] = [L.T]
        ;        [.5VxTx + .5VyTy + .5] = [V.T]
        ;
        ;   
        ; 
        ; texcoord set 1 output = .5Lx, .5Ly, .5   //tangent space light vector (last component zeroed out)
        ; texcoord set 2 output = .5Vx, .5Vy, .5   //tangent space reflection vector (last component zeroed out)

        ; This sample expects the incoming vertex data to be set up as follows:
        ;
        ; v0     - Vertex Position
        ; v3	 - Vertex Normal
        ; v7	 - Vertex 2D Bumpmap Texture Coords
        ; v8	 - Vertex Tangent (normalized assumed to be positive v direction for tangent space)
        ; v9   - vertex binormal
        ; This sample expects the constant store to be set up in the following manner:
        ;
        ; c16..c19 - Composite World-View-Projection Matrix

        ; c28      - Model Space Camera Position
        ; c32      - Model Space Light position
        ; c95      - 0, .5, 1, 2


        vs.1.0

        ; Convert from D3DColor to -1 to 1
        mad  r7, v3, c95.wwwz, -c95.zzzx ; Normal   = (v3*2.0)-1.0
        mad  r8, v8, c95.wwwz, -c95.zzzx ; TangentU = (v8*2.0)-1.0
        mad  r9, v9, c95.wwwz, -c95.zzzx ; TangentV = (v9*2.0)-1.0

        ;derive per vertex eye vector using camera position   
        ;find view vector		
        ; (if assuming an infinite viewer replace below 4 lines with mov (r1,c28) )
        add		r2, c28, -v0	;viewer direction V

        ;transform view vector into tangent space
        dp3      r3.x, r2, r9
        dp3      r3.y, r2, r8
        dp3      r3.zw, r2, r7     ;z is only needed for normalization

        ;normalize vector after reflection
        dp3		r11.x, r3, r3	   ;magnitude
        rsq		r11.y, r11.x	   ;normailize
        mul		r3, r3, r11.y	   ;tangent space view vector in r3

        mad      r3, r3, c95.yyxx, c95.xxyx     ; 0.5Vx, 0.5Vy, 0.5, 0

        ;get normalized tangent space light vector
        add      r2, c32, -v0

        ;transform light vector into tangent space
        dp3      r4.x, r2, r9
        dp3      r4.y, r2, r8
        dp3      r4.zw, r2, r7

        ;normalize vector after reflection
        dp3		r11.x, r4, r4	   ;magnitude
        rsq		r11.y, r11.x	   ;normailize
        mul		r4, r4, r11.y	   ;tangent space reflection vector in r3

        mad      r4, r4, c95.yyxx, c95.xxyx     ; 0.5Lx, 0.5Ly, 0.5, 0


        ; OutPos = ObjSpacePos * Composite World-View-Projection Matrix
        m4x4   oPos, v0, c16

        ; Color 1 gets diffuse color
        ;mov oD0, v4


        mov oT0.xy, v7       		;passthrough texcoord 0 for bump map addressing
        mov oT1.xy, v7       		;passthrough texcoord 1 for base map addressing

        mov oT2.xyz, r4		      ;
        mov oT3.xyz, r3	         ;

    };

pixelshader ps11_AnisoLight = asm
{
    ;
    ; t2 contains tangent-space L vector          ; 0.5Lx, 0.5Ly, 0.5, 0
    ; t3 contains tangent-space reflection vector ; 0.5Vx, 0.5Vy, 0.5, 0

    ;
    ; Map bound at stage 0 is a normal map
    ; Map bound at stage 3 is a T.L x T.V map as the z positive face of a cube map
    ;
    ps.1.1
    def c0, 0.0, 0.0, 0.0, 0.0

    tex t0                 ; Contains direction of anisotropy in tangent space
    tex t1                 ; base map

    texm3x2pad t2, t0_bx2  ; Perform second row of matrix multiply.
    texm3x2tex t3, t0_bx2  ; Perform second row of matrix multiply to get a
                           ; 3-vector with which to sample texture 3, which is
				           ; a look-up table for aniso lighting

    mul r0, t3, t1         ;basemap * diffuse    glossmap* specular
    add r0, r0, r0.a       ;basemap * diffuse + glossmap* specular
    mad r0, t1, c7, r0     ;+= ambient * basemap
};

String ps11_AnisoLight_desc = "PS 1.1 - Per Pixel Anisotropic Lighting";

technique ps11_AnisoLight
{
    pass P0 
    {
        VertexShader = <vAnisoLight>;
        VertexShaderConstant[16] = <mWVP>;  // World*View*Proj Matrix
        VertexShaderConstant[20] = <mW1>;   // World Inverse
        VertexShaderConstant[28] = <pOV>;   // Object space Viewer position
        VertexShaderConstant[32] = <pOL>;   // Object space Light position
        VertexShaderConstant[95] = <cnst>;

        Texture[0]   = <tAnisoDirection>;
	    AddressU[0]  = Wrap;
	    AddressV[0]  = Wrap;
        MagFilter[0] = Linear;
        MinFilter[0] = Linear;
        MipFilter[0] = Linear;

        Texture[1]   = <tGloss>;
	    AddressU[1]  = Wrap;
	    AddressV[1]  = Wrap;
        MagFilter[1] = Linear;
        MinFilter[1] = Linear;
        MipFilter[1] = Linear;

        Texture[3]   = <tAniso>;
	    AddressU[3]  = Wrap;
	    AddressV[3]  = Wrap;
        MagFilter[3] = Linear;
        MinFilter[3] = Linear;
        MipFilter[3] = Linear;

        PixelShaderConstant[7] = <cAmbient>;
        PixelShader  = <ps11_AnisoLight>;
    }
}
