// Software vertex shader generated by Wild Magic.
//
// var float3   kModelPosition       $vin.POSITION
// var float3   kModelNormal         $vin.NORMAL
// var float2   kInRandomTCoord      $vin.TEXCOORD0
// var float4   kClipPosition        $vout.POSITION
// var float4   kVertexColor         $vout.COLOR
// var float2   kContrastTCoord      $vout.TEXCOORD0
// var float2   kOutRandomTCoord     $vout.TEXCOORD1
// var float2   kPaperTCoord         $vout.TEXCOORD2
// var float4x4 WVPMatrix            c[0]
// var float3   Light0ModelDirection c[4]
// var float3   Light1ModelDirection c[5]
// var float    Constants            c[6]

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

namespace Wm4
{

void v_Charcoal (const float* afRegister, const float* afInVertex,
    float* afOutVertex)
{
    // Get the register items.
    const Matrix4f& rkWVPMatrix = *(const Matrix4f*)&afRegister[0];
    const Vector3f& rkLight0ModelDirection =
        *(const Vector3f*)&afRegister[16];
    const Vector3f& rkLight1ModelDirection =
        *(const Vector3f*)&afRegister[20];
    float fAmbientIntensity = afRegister[24];
    float fContrastExponent = afRegister[25];

    // Get the input items.
    Vector4f kModelPosition(afInVertex[0],afInVertex[1],afInVertex[2],1.0f);
    const Vector3f& rkModelNormal = *(const Vector3f*)&afInVertex[3];
    const Vector2f& rkInRandomTCoord = *(const Vector2f*)&afInVertex[6];

    // Access the output items.
    Vector4f& rkClipPosition = *(Vector4f*)&afOutVertex[0];
    ColorRGBA& rkVertexColor = *(ColorRGBA*)&afOutVertex[4];
    Vector2f& rkContrastTCoord = *(Vector2f*)&afOutVertex[8];
    Vector2f& rkOutRandomTCoord = *(Vector2f*)&afOutVertex[10];
    Vector2f& rkPaperTCoord = *(Vector2f*)&afOutVertex[12];

    // *** program ***

    // Transform the position from model space to clip space.
    rkClipPosition = kModelPosition*rkWVPMatrix;

    // Calculate lighting intensity with two diffuse lights and ambient light.
    // Only the intensity is computed so that the output color is gray scale.
    float fDiffuse1 = Saturate(-(rkModelNormal.Dot(rkLight0ModelDirection)));
    float fDiffuse2 = Saturate(-(rkModelNormal.Dot(rkLight1ModelDirection)));
    float fIllumination = Saturate(fDiffuse1 + fDiffuse2 + 
        fAmbientIntensity);

    // Enhance the contrast of the computed color.
    float fContrastIllumination = Mathf::Pow(fIllumination,fContrastExponent);

    rkVertexColor = ColorRGBA(fContrastIllumination,fContrastIllumination,
        fContrastIllumination,fContrastIllumination);

    // The first texture coordinate is a lookup into a 2D texture image of
    // random values.  The coordinate will be used to find the s coordinate
    // for lookup into the contrast texture.  The random map produces a
    // random s coordinate at each fragment, as sometimes the given model st
    // coordinates produce nasty banding artifacts if they are just
    // interpolated across the polygons.  The t coordinate is the gray scale
    // color value of the fragment.
    rkOutRandomTCoord = rkInRandomTCoord;

    // Compute the texture coordinate for the contrast map using the lookup
    // produced by the random map.
    rkContrastTCoord.X() = 0.0f;
    rkContrastTCoord.Y() = fContrastIllumination;

    // The second texture is a paper texture that is overlaid on the screen.
    // Determine the screen-space texture coordinates for this vertex.  Some
    // of the models looked odd if alpha blending was ued, so instead just
    // draw with no blending.  Convert screen coordinates from [-1,1] to [0,1]
    // for texture lookup.
    float fInverseW = 1.0f/rkClipPosition.W();
    rkPaperTCoord.X() = (rkClipPosition.X()*fInverseW + 1.0f)*0.5f;
    rkPaperTCoord.Y() = (rkClipPosition.Y()*fInverseW + 1.0f)*0.5f;
}

WM4_IMPLEMENT_VPROGRAM(Charcoal);
WM4_REGISTER_VPROGRAM(Charcoal);

}
