-- glslfx version 0.1

-- configuration
{
    "techniques": {
        "default": {
            "skinPointsLBSKernel": {
                "source": [ "Compute.SkinPointsLBS" ]
             },
            "skinPointsSimpleKernel": {
                "source": [ "Compute.SkinPointsSimple" ]
             }
        }
    }
}

-- glsl Compute.SkinPointsLBS

const float EPS = 1e-5;

void compute(int index)
{
    // model space -> bind space
    mat4 geomBindXform = HdGet_geomBindXform();

    vec3 restP = HdGet_restPoints(index);

    // apply blend shapes
    int numBlendShapeOffsetRanges = HdGet_numBlendShapeOffsetRanges();
    if (index < numBlendShapeOffsetRanges) {
        ivec2 blendShapeOffsetRange = HdGet_blendShapeOffsetRanges(index);
        for (int i = blendShapeOffsetRange.x; i < blendShapeOffsetRange.y; ++i) {
            vec4 offset = HdGet_blendShapeOffsets(i);
            int shapeIndex = int(offset.w);
            float weight = HdGet_blendShapeWeights(shapeIndex);
            restP += offset.xyz * weight;
        }
    }
    vec4 initP = geomBindXform * vec4(restP, 1);
    
    int numInfluencesPerComponent = HdGet_numInfluencesPerComponent();
    vec3 p;
    if (numInfluencesPerComponent > 0) {
        p = vec3(0,0,0);

        bool constantPointInfluence = HdGet_hasConstantInfluences();
        int offset = constantPointInfluence? 0 : numInfluencesPerComponent*index;

        for (int i = 0; i < numInfluencesPerComponent; i++) {
            vec2 influence = HdGet_influences(offset + i);
            float jointWeight = influence.y;

            if (jointWeight > EPS) {
                int jointIdx = int( influence.x );
                mat4 skinningXform = HdGet_skinningXforms(jointIdx);

                p += ((skinningXform * initP) * jointWeight).xyz;
            }
        }
    } else {
        p = initP.xyz;
    }

    // skel space -> world space -> model space
    // XXX: Casts to mat4 below are necessary because the matrices passed
    // down use doubles and not floats.
    mat4 skelToPrimLocal = mat4( HdGet_primWorldToLocal() ) *
                           mat4( HdGet_skelLocalToWorld() );
    p = (skelToPrimLocal * vec4(p,1)).xyz;

    HdSet_skinnedPoints(index, p);
}


-- glsl Compute.SkinPointsSimple

void compute(int index)
{
    // This is simple joint-constraint skinning model.

    mat4 geomBindXform = HdGet_geomBindXform();
    int jointIndex = int( HdGet_influences(index).x );
    mat4 skinningXform = HdGet_skinningXforms(jointIndex);
    
    // model space -> bind space -> skel space
    vec4 p = skinningXform * geomBindXform * vec4(HdGet_restPoints(index), 1);
    
    // skel space -> world space -> model space
    // XXX: Casts to mat4 below are necessary because the matrices passed
    // down use doubles and not floats.
    mat4 skelToPrimLocal = mat4( HdGet_primWorldToLocal() ) *
                           mat4( HdGet_skelLocalToWorld() );
    p = skelToPrimLocal * p;

    HdSet_skinnedPoints(index, p.xyz);
}
