/*
==========================================================================================
 Cg Acceleration Research

 Edgar Velázquez Armendáriz - edgar [at] graphics [dot] cornell [dot] edu
------------------------------------------------------------------------------------------
 pointProjection.cg

 Point cloud projection shaders using MRT. Requires fp40 profile.
==========================================================================================
*/


/* Vertex information to be transfered */
struct vertexInfo {
    float4 pos                  : POSITION;
    half2 uv                    : TEXCOORD0;
    half4 color                 : COLOR0;
    half4 colorSec              : COLOR1;
    half2 subPixel;
};
    

// vp40: # 18 instructions, 2 R-regs
void vertMain(  uniform float4x4 ModelViewProj  : state.matrix.mvp,
                uniform half2 c,                // Vector <width/2, height/2> for subpixel transformation
                in  vertexInfo IN,
                out vertexInfo OUT  ) {
                
    // Transformed position of the vertex into clip coordinates
    OUT.pos = mul(ModelViewProj, IN.pos);

    // Force points into clipping plane, to avoid the backgroud points to be
    // deleted by the depth cull
    OUT.pos.z = clamp(OUT.pos.z, -1e38, OUT.pos.w * (0.999999523162841796875));
    
    // Just copy the input color, and the secondary color which contains the encoded pointID
    OUT.color    = IN.color;
    OUT.colorSec = IN.colorSec;
    
    // The rectangle texture coordinates encode the index of the vertex into the
    // original array of data, in such a way that all its original data is read from
    // the packed texture
    OUT.uv = IN.uv;
    
    // Get the pixel mapping, integer and fractional part (characteristic and mantissa)
    const half2 gamma = c * OUT.pos.xy / OUT.pos.w + c;
    
    // The fractional part is stored in a varying parameter:
    // Each mantissa will give me the information about subpixel location
    OUT.subPixel    = frac(gamma);
    OUT.subPixel.y  = 1 - OUT.subPixel.y;   // Calculated with origin on bottom left corner, It must
                                            // be in the upper left corner.
        
}


// fp40: # 15 instructions, 1 R-regs, 1 H-regs
void fragMain(  uniform samplerRECT packData    : TEXUNIT0,
                in  vertexInfo IN,
                in  float3 pos                  : WPOS,
                out float depth                 : DEPTH,
                out half4 outputs[3]            : COLOR0    ) {
                
    // UPDATE TO REFLECT CHANGES IN ENVIRONMENT
    const half MAX_AGE  = 255;      // [0,255]
    const half FLAGS    = 64;       // [0,255]      // FLAGS == 0x40
    
    // After the texture operation, do some math to cover the latency
    half4 idAgePacked = texRECT(packData, IN.uv);

    // Subpixel info
    half2 subPixV   = floor(half2(4,4) * IN.subPixel);
    half subPix     = 1/255.0h * (4*subPixV.y + subPixV.x);     // subPix (not scaled) is in the range [0, 15]
    
    // The secondary color contains the pointID, with the LSB in R and the MSB in B, so I just
    // need to copy that information
    half4 idVertex = half4(FLAGS/255.0, IN.colorSec.rgb);

    // If this is an invalid point, because of the age, discard
    if (idAgePacked.r >= MAX_AGE/255.0h) { outputs[0] = half4(1,0,0, subPix); }//discard; }


    // Normal color, it also copies the subpixel info into the final RGBA texture, 
    // ready to be attached to the EPI-GPU.
    outputs[0] = half4(IN.color.rgb, subPix);

    // The final output contains the Flags in R and the pointID splitted in GBA
    outputs[1] = idVertex;
    
    // In the third render buffer, I will store:
    //   r - Priority
    //   g - seqnum
    //   b - flags/seqnum info
    //   a - 0 as flag -> invalid pixels have a = 1
    half priority = saturate(idAgePacked.r/2.0 - 8/255.0);      // priority = max(0,age-16) / 2
    outputs[2] = half4(priority, IN.color.a, 1/255.0h * FLAGS + IN.color.a, 0);
    
}