/*
 * Disk light, an example of a "pseudo area light".
 * The disk is in the x-y plane, centered at the origin.
 * The sample positions are randomly distributed on the disk;
 * they are chosen in a uniform, stratified manner.
 * Occlusion is computed with ray tracing.
 * The illuminate point is chosen such that L.N is 1 in the diffuse
 * calculation in the surface shader.
 */
light
disklight(
    float intensity = 1,
    color lightcolor = 1,
    float falloff = 2,   /* 0 = none, 1 = linear, 2 = squared, ... */
    float radius = 1,   /* radius of the disc */
    float samples = 16,   /* number of sample points on the light source */
    output float __nonspecular = 1
)
{
    float rsamples, anglesamples;
    float i, j;
    color c;
    vector l, ln, Nn = normalize(N);
    point p = Ps + N;   /* point above Ps to get N.L = 1 in surf. shader */
    float angle, r, dist, LdotN;

    rsamples = floor(sqrt(samples));
    anglesamples = floor(samples/rsamples);

    emit(p) {
		setmessage ("__nonspecular", __nonspecular);
        for (j = 0; j < rsamples; j += 1)  {
            for (i = 0; i < anglesamples; i += 1)  {
                /* Compute uniformly distributed point (x,y) on unit disc */
                angle = 2 * M_PI * (i + random()) / anglesamples;
                r = radius * sqrt((j + random()) / rsamples);
                /* Compute point p on rectangle */
                p = point ("shader", r * cos(angle), r * sin(angle), 0);
                /* Compute distance from point p to surface point Ps */
                l = p - Ps;
                dist = length(l);
                ln = l / dist;
                /* Compute light from point p to surface point Ps */
                LdotN = dot(ln,Nn);
	        if (LdotN > 0) {
                    c = intensity * lightcolor;
                    c *= pow(dist, -falloff);   /* distance falloff */
                    c *= transmission(Ps, p);   /* ray traced occlusion */
                    c *= LdotN;   /* Lambert's cosine law at the surface */
                    Cl += c;
                }
            }
        }
        Cl /= rsamples * anglesamples; /* can be different from 'samples' */
    }
}
