/////////////////////////////////////////////////////////////////////////////
// brushedmetal.gsl - metal surface with brushed appearance and 
//                    optional reflections
//
// Parameters:
//   Ka, Kd, Ks - The usual meaning
//   uroughness, vroughness - separate roughnesses for the two primary
//             directions.
//   projection - the projection used to find the grain pattern: "st", "ts",
//             or "Pref"
//   shadingspace - the space of the projection for the grain
//   grainamp - amplitude of the grain (0 means no grain)
//   grainfreq - frequency of the grains
//   graindir - direction of the grain (used if projection is "Pref")
//   Kr - coefficient for mirror-like reflections of environment
//   blur - how blurry are the reflections? (0 = perfectly sharp)
//   envname - name of environment map, or geometry set for ray tracing
//             (setting to "" means no mirror reflections)
//   envspace - coord sys for env map lookups (ignored
//         for ray tracing)
//   samples - how many samples, for ray tracing blurry reflections
//   twosided - if nonzero both sides of the surface are shiny, otherwise
//       only the "outside" (where the surface normal points) will
//       have reflections.  This can be an important optimization,
//       especially when ray tracing.
//   Pref - if supplied, a reference mesh (defaults to the real geometry)
//
/////////////////////////////////////////////////////////////////////////////
// Copyright 2004 NVIDIA Corporation.  All Rights Reserved.
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// 
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA nor the names of its contributors
//   may be used to endorse or promote products derived from this software
//   without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// (This is the Modified BSD License)
/////////////////////////////////////////////////////////////////////////////




#include "noises.h"
#include "material.h"


surface
brushedmetal
  [[ string description = "Brushed anisotropic metal with procedural grain" ]]
(
    float Ka = 1
        [[  string description = "Ambient scaling",
            float UImin = 0, float UIsoftmax = 1 ]],
    float Kd = 0.1
        [[  string description = "Diffuse scaling",
            float UImin = 0, float UIsoftmax = 0.5 ]],
    float Ks = 0.8
        [[  string description = "Specular scaling",
            float UImin = 0, float UIsoftmax = 1 ]],
    float uroughness = 0.2
        [[  string description = "Surface roughness in u direction",
            float UImin = 0, float UImax = 1,
            string UIenabler = "Ks" ]],
    float vroughness = 0.5
        [[  string description = "Surface roughness in v direction",
            float UImin = 0, float UImax = 1,
            string UIenabler = "Ks" ]],

    string projection = "st"
        [[  string description = "Projection to use for grain",
            string UItype = "enum:st,ts,Pref",
            string UIgroupbegin = "Grain" ]],
    float grainfreq = 400
        [[  string description = "Grain frequency" ]],
    float grainamp = .75
        [[  string description = "Grain amplitude" ]],
    vector graindir = vector ("shader",0,0,1)
        [[  string description = "3D Grain direction" ]],
    float s = u
        [[  string description = "s grain coordinate (defaults to u)" ]],
    float t = v
        [[  string description = "t grain coordinate (defaults to v)" ]],
    string shadingspace = "shader"
        [[  string description = "Shading space (only used for proj='Pref')",
            string UItype = "coordsys" ]],
    point Pref = P
        [[  string description = "Reference pose (defaults to P)",
            string UIgroupend = "Grain"  ]],

    float Kr = 0.25
        [[  string description = "Reflectivity / Environment scaling",
            string UIlabel = "Reflectivity",
            float UImin = 0, float UIsoftmax = 1,
            string UIgroupbegin = "Reflections" ]],
    float blur = 0
        [[  string description = "Environment blur",
            string UIenabler = "Kr",
            float UImin = 0, float UIsoftmax = 1 ]],
    string envname = ""
        [[  string description = "Map or geometry set name for reflections",
            string UIlabel = "Environment name",
            string UIenabler = "Kr",
            string UItype = "environment" ]],
    string envspace = "world"
        [[  string description = "Coordinate system for environment map lookup",
            string UIlabel = "Environment space",
            string UIenabler = "Kr",
            string UItype = "coordsys" ]],
    float samples = 1
        [[  string description = "Environment samples (for ray tracing)",
            string UIlabel = "Environment samples",
            string UIenabler = "Kr",
            string UItype = "int", float UImin = 1, float UIsoftmax = 64 ]],
    float twosided = 0
        [[  string description = "Two-sided reflections",
            string UIenabler = "Kr",
            string UItype = "bool",
            string UIgroupend = "Reflections" ]]
  )
{
    point Pgrain;
    vector T;
    if (projection == "st") {
	Pgrain = point (s, t, 1);
        T = dPdu;
    } else if (projection == "ts") {
	Pgrain = point (t, s, 1);
        T = dPdv;
    } else {
	/* any other projection */
	point Pshad = transform(shadingspace, Pref);
	Pgrain = Pshad;
        T = graindir;
    }
    Pgrain *= grainfreq;
    Pgrain *= vector(.025,1,1);  // Squash grains

    float dgrain = sqrt(area(Pgrain));
    float grain = 0.5 + (grainamp/2) * filteredsnoise(Pgrain, dgrain);

    normal Nf = faceforward (normalize(N), I);
    vector IN = normalize(I);
    color Cbase = C;
    C = MaterialBrushedMetal (Nf, Cbase*grain, Ka, Kd, Ks, 
                              normalize(T), uroughness, vroughness);
    vector R = reflect (IN, Nf);
    // kr is reflectivity, but set it to zero if we're looking at the
    // back of a surface that's "silvered" on only one side
    float kr = (twosided == 0 && dot(N,I) > 0) ? 0 : Kr;
    C += kr * Cbase * Environment (envname, R, envspace,
                                   blur, samples, kr);

    // Handle opacity
    C *= opacity;
}
