/*
 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

<<
private FloatBuffer kvals;

private float getSurfaceScale() {
    return getEffect().getSurfaceScale();
}

private float getDiffuseConstant() {
    return getEffect().getDiffuseConstant();
}

private float getSpecularConstant() {
    return getEffect().getSpecularConstant();
}

private float getSpecularExponent() {
    return getEffect().getSpecularExponent();
}

private float[] getNormalizedLightPosition() {
    return getEffect().getLight().getNormalizedLightPosition();
}

private float[] getLightPosition() {
    com.sun.scenario.effect.light.PointLight plight =
        (com.sun.scenario.effect.light.PointLight)getEffect().getLight();
    return new float[] { plight.getX(), plight.getY(), plight.getZ() };
}

private float[] getLightColor() {
    return getEffect().getLight().getColor().getPremultipliedRGBComponents();
}

private float getLightSpecularExponent() {
    return ((com.sun.scenario.effect.light.SpotLight)getEffect().getLight()).getSpecularExponent();
}

private float[] getNormalizedLightDirection() {
    return ((com.sun.scenario.effect.light.SpotLight)getEffect().getLight()).getNormalizedLightDirection();
}

private FloatBuffer getKvals() {
    Rectangle bumpImgBounds = getInputNativeBounds(0);
    float xoff = 1f / bumpImgBounds.width;
    float yoff = 1f / bumpImgBounds.height;

    float[] kx = {
        -1, 0, 1,
        -2, 0, 2,
        -1, 0, 1,
    };
    float[] ky = {
        -1, -2, -1,
         0,  0,  0,
         1,  2,  1,
    };
    if (kvals == null) {
        kvals = BufferUtil.newFloatBuffer(8*4);
    }
    kvals.clear();
    int kidx = 0;
    float factor = -getSurfaceScale() * 0.25f;
    for (int i = -1; i <= 1; i++) {
        for (int j = -1; j <= 1; j++) {
            if (i != 0 || j != 0) {
                kvals.put(j*xoff);
                kvals.put(i*yoff);
                kvals.put(kx[kidx] * factor);
                kvals.put(ky[kidx] * factor);
            }
            kidx++;
        }
    }
    kvals.rewind();
    return kvals;
}

private int getKvalsArrayLength() {
    return 8;
}
>>

param sampler bumpImg;
param sampler origImg;
param float diffuseConstant;
param float specularConstant;
param float specularExponent;
param float3 lightColor;
// value for each location in the Sobel kernel:
//   kvals[i].x = offsetX[i]
//   kvals[i].y = offsetY[i]
//   kvals[i].z = kernelX[i]
//   kvals[i].w = kernelY[i]
param float4 kvals[8];

// (placeholder for pluggable light position/color declarations)
%s

void main()
{
    float4 orig = sample(origImg, pos1);

    // calculate normal
    int i;
    float3 sum = float3(0.0, 0.0, 1.0);
    unroll(8, 0) for (i = 0; i < 8; i++) {
        sum.xy += kvals[i].zw * sample(bumpImg, pos0 + kvals[i].xy).a;
    }
    float3 N = normalize(sum);

    // calculate light unit vector and color for this position
    // (placeholder for pluggable light position/color calculations)
    %s

    // calculate halfway unit vector
    float3 E = float3(0.0, 0.0, 1.0);
    float3 H = normalize(Lxyz + E);

    // calculate diffuse element
    float4 D;
    D.rgb = diffuseConstant * dot(N, Lxyz) * Lrgb;
    D.rgb = clamp(D.rgb, 0.0, 1.0);
    D.a = 1.0;

    // calculate specular element
    float4 S;
    float NdotH = dot(N, H);
    S.rgb = specularConstant * pow(NdotH, specularExponent) * Lrgb;
    S.a = max(S.r, S.g);
    S.a = max(S.a, S.b);

    // modulate diffuse and specular elements with source image
    orig *= D;
    S *= orig.a;
    color = S + (orig * (1.0-S.a));
}
