// Software vertex shader generated by Wild Magic.
//
// var float3   kModelPosition      $vin.POSITION
// var float3   kModelNormal        $vin.NORMAL
// var float4   kClipPosition       $vout.POSITION
// var float    fReflectFactor      $vout.COLOR
// var float2   kRefractVector      $vout.TEXCOORD0
// var float2   kReflectVector      $vout.TEXCOORD1
// var float4x4 WVPMatrix           c[0]
// var float4x4 WMatrix             c[4]
// var float3   CameraWorldPosition c[8]
// var float4   FresnelConstants    c[9]

#include "Wm4SoftRenderer.h"
#include "Wm4Matrix4.h"
#include "Wm4Vector2.h"
#include "Wm4Vector3.h"

namespace Wm4
{

void v_Refraction (const float* afRegister, const float* afInVertex,
    float* afOutVertex)
{
    // Get the register items.
    const Matrix4f& rkWVPMatrix = *(const Matrix4f*)&afRegister[0];
    const Matrix4f& rkWMatrix = *(const Matrix4f*)&afRegister[16];
    const Vector3f& rkCameraWorldPosition =
        *(const Vector3f*)&afRegister[32];
    const Vector4f& rkFresnelConstants = *(const Vector4f*)&afRegister[36];

    // Get the input items.
    Vector4f kModelPosition(afInVertex[0],afInVertex[1],afInVertex[2],1.0f);
    Vector4f kModelNormal(afInVertex[3],afInVertex[4],afInVertex[5],0.0f);

    // Access the output items.
    Vector4f& rkClipPosition = *(Vector4f*)&afOutVertex[0];
    float& rfReflectFactor = afOutVertex[4];
    Vector2f& rkRefractVector = *(Vector2f*)&afOutVertex[5];
    Vector2f& rkReflectVector = *(Vector2f*)&afOutVertex[7];

    // *** program ***

    // Transform the position from model space to clip space.
    rkClipPosition = kModelPosition*rkWVPMatrix;
    
    // Transform the position from model space to world space.
    Vector3f kWorldPosition = (Vector3f)(kModelPosition*rkWMatrix);

    // Transform the normal from model space to world space.  In case the
    // model-to-world matrix has nonunit scales, the resulting vector must
    // be normalized.
    Vector3f kWorldNormal = (Vector3f)(kModelNormal*rkWMatrix);
    kWorldNormal.Normalize();

    // Calculate the eye direction.
    Vector3f kEyeDirection = kWorldPosition - rkCameraWorldPosition;
    kEyeDirection.Normalize();

    // Calculate the reflection vector.  Since the eye direction and the
    // world normal are unit length vectors, the reflection vector is already
    // unit length.
    Vector3f kReflection = Reflect(kEyeDirection,kWorldNormal);
    rkReflectVector[0] = 0.5f*kReflection[1] + 0.5f;
    rkReflectVector[1] = 0.5f*kReflection[2] + 0.5f;

    // Get the eye vector and transform into spherical coordinates.  Because
    // we are using a sphere map that is in the x direction, we will transform
    // the y and z coordinates into the texture coordinates.  Since the eye
    // direction and the world normal are unit length vectors, the refraction
    // vector is already unit length.
    Vector3f kRefraction = Refract(kEyeDirection,kWorldNormal,
        rkFresnelConstants[3]);
    rkRefractVector[0] = 0.5f*kRefraction[1] + 0.5f;
    rkRefractVector[1] = 0.5f*kRefraction[2] + 0.5f;

    // Calculate the reflection factor.
    rfReflectFactor = rkFresnelConstants[0] + rkFresnelConstants[1] *
        Mathf::Pow(1.0f + kEyeDirection.Dot(kWorldNormal),
        rkFresnelConstants[2]);
}

WM4_IMPLEMENT_VPROGRAM(Refraction);
WM4_REGISTER_VPROGRAM(Refraction);

}
