<arbvp>
  <!-- This should be directional light from the sun -->
  <variablemap variable="light 0 position" destination="register 0" />
  <variablemap variable="light 0 diffuse" destination="register 1" />
  <variablemap variable="beta' 1" destination="register 2" />
  <variablemap variable="beta' 2" destination="register 3" />
  <variablemap variable="beta1 + beta2" destination="register 4" />
  <variablemap variable="1 over beta1 + beta2" destination="register 5" />
  <variablemap variable="hg" destination="register 7" />
  <variablemap variable="inscattering term" destination="register 8" />
  <variablemap variable="mat reflection" destination="register 9" />
  
  <?if vars."tex normal"?>
    <!-- some things only needed by when using the PPL base map -->
    <variablemap variable="texture lod distance" destination="register 6"/>
  <?endif?>
  
  <program>
    <![CDATA[
      !!ARBvp1.0
      #---------------------------------------------------
      # light scattering extinction and inscatter
      #---------------------------------------------------
      # Incoming program constants
      PARAM mv[4]		= { state.matrix.modelview };
      PARAM mvi[4]		= { state.matrix.modelview.inverse };
      PARAM mvp[4]		= { state.matrix.mvp };
      PARAM ones		= { 1, 1, 1, 0 };
      PARAM log_2_e		= { 1.4427, 1.4427, 1.4427, 1.4427 };
      PARAM lightIntensity      = { 100, 100, 100, 0 };
      PARAM lightPos		= program.local[0];
      PARAM lightDiffuse 	= program.local[1];
      # Several constant specified by the program (scattering factors)
      PARAM cBd1		= program.local[2];
      PARAM cBd2		= program.local[3];
      PARAM cB1plusB2		= program.local[4];
      PARAM c1oB1plusB2		= program.local[5];
      PARAM cHg			= program.local[7];
      PARAM cInscatterTerm	= program.local[8];
      
      PARAM mat_reflection	= program.local[9];
      PARAM eyePos		= { 0, 0, 0, 1};
      
      # Input vertex info
      ATTRIB iPos		= vertex.position;
      
      # Output information
      OUTPUT oPos		= result.position;
      OUTPUT oCol0		= result.color;
      ATTRIB iTex0		= vertex.texcoord[0];
      OUTPUT oTex0		= result.texcoord[0];
    ]]>
    <?if vars."tex normal"?>
      PARAM loddist             = program.local[6];
      OUTPUT oLightDir		= result.texcoord[1];
      OUTPUT oLodBlend		= result.texcoord[2];
      TEMP lodblend;
    <?endif?>
    <![CDATA[
      # Temporaries
      TEMP worldPos;
      TEMP objLight;
      TEMP objEye;
      TEMP theta;
      TEMP theta2;
      TEMP temp1;
      TEMP temp2;
      TEMP temp3;
      TEMP temp4;
      TEMP extinction;
      TEMP inscatter;
      
      MOV oTex0, iTex0;
      
      ###
      # transform positon to perspective space
      DP4 oPos.x, mvp[0], iPos;
      DP4 oPos.y, mvp[1], iPos;
      DP4 oPos.z, mvp[2], iPos;
      DP4 oPos.w, mvp[3], iPos;
      
      ###
      # transform light to objSpace
      DP4 objLight.x, mvi[0], lightPos;
      DP4 objLight.y, mvi[1], lightPos;
      DP4 objLight.z, mvi[2], lightPos;
      DP4 objLight.w, mvi[3], lightPos;
      
      ###
      # transform eye to objSpace
      DP4 objEye.x, mvi[0], eyePos;
      DP4 objEye.y, mvi[1], eyePos;
      DP4 objEye.z, mvi[2], eyePos;
      DP4 objEye.w, mvi[3], eyePos;
      
      ###
      # Find and normalize light vector from vertex
      ADD objLight, objLight, -iPos;
      DP3 objLight.w, objLight, objLight;
      RSQ objLight.w, objLight.w;
      MUL objLight, objLight, objLight.w;
      
      ###
      # Find and normalize eye vector from vertex 
      ADD objEye, objEye, -iPos;
      DP3 objEye.w, objEye, objEye;
      RSQ objEye.w, objEye.w;
    ]]>
    <?if vars."tex normal"?>
      MUL lodblend, objEye.w, loddist;
      RCP lodblend.x, lodblend.x;
      MIN lodblend.x, lodblend.x, eyePos.w;
      MOV oLightDir, objLight;
      MOV oLodBlend, lodblend.xxxx;
    <?endif?>
    <![CDATA[
      RCP theta.z, objEye.w;
      MUL objEye, objEye, objEye.w;
      
      ###
      # Find angle between light and viewdir
      # x = cos(theta) = V.L
      # y = cos^2(theta) + 1 = Phase1(theta)
      DP3 theta.x, objEye, objLight; 
      MAD theta.y, theta.x, theta.x, ones.x;

      ###
      # hg = [1-g^2, 1+g, -2g]
      # temp1.x = 1+g - 2g * cos(theta)
      MAD temp1.x, cHg.z, theta.x, cHg.y;
      ###
      # temp1.x = 1 / (1+g - 2g * cos(theta))^1/2
      RSQ temp1.x, temp1.x;
      ### 
      # temp1.y = 1 / (1+g - 2g * cos(theta))^1
      MUL temp1.y, temp1.x, temp1.x;
      ###
      # temp1.x = 1 / (1+g - 2g * cos(theta))^3/2
      MUL temp1.x, temp1.y, temp1.x;
      ###
      # theta.w = (1-g^2) / (1+g-2g*cos(theta)) ^ (3/2) = Phase2(theta)
      MUL theta.w, temp1.x, cHg.x; 
      
      
      ###
      # compute the extinction term
      # extinction = -(beta_1+beta_2) * s
      MUL extinction, cB1plusB2, -theta.z;
      ###
      # extinction = -(beta_1+beta_2) * s * log_2(e)
      MUL extinction, extinction, log_2_e;
      ###
      # extinction = e^(-(beta1 +beta2) * s)
      EX2 extinction.x, extinction.x;
      EX2 extinction.y, extinction.y;
      EX2 extinction.z, extinction.z;
      
      ###
      # compute the inscattering term
      # inscatter = Beta'_1 * Phase_1(theta)
      MUL inscatter, cBd1, theta.y;
      ###
      # temp1 = Beta'_2 * Phase_2(theta)
      MUL temp1, cBd2, theta.w;
      ###
      # temp2 = 1 - e^(-(beta1 +beta2) * s)
      ADD temp2, ones, -extinction;
      ###
      # temp3 = 1 / (beta1 + beta2)
      RCP temp3.x, cB1plusB2.x;
      RCP temp3.y, cB1plusB2.y;
      RCP temp3.z, cB1plusB2.z;
      
      ###
      # inscatter = Beta'_1 * Phase_1(theta) + Beta'_2 * Phase_2(theta)
      ADD inscatter, inscatter, temp1;
      ###
      # inscatter = (Beta'_1 * Phase_1(theta) + Beta'_2 * Phase_2(theta))
      #     * (1 - e^(-(beta1 +beta2) * s))
      MUL inscatter, inscatter, temp2;
      ###
      # inscatter = (Beta'_1 * Phase_1(theta) + Beta'_2 * Phase_2(theta))
      #     * (1 - e^(-(beta1 +beta2) * s)) / beta_1_plus_beta_2
      MUL inscatter, inscatter, temp3;
      
      ###
      # Apply inscattering contribution factors
      MUL inscatter, inscatter, cInscatterTerm.y;

      ###
      # Apply light color and intensity
      MUL inscatter, inscatter, lightDiffuse;
      MUL inscatter, inscatter, lightIntensity;
      #MUL inscatter, inscatter, lightDiffuse.w;
      
      # Pass the diffuse light modulated with inscattering
      MOV oCol0, inscatter;
      
      END
    ]]>
  </program>
</arbvp>
