// Copyright (C) 1997-2004 Alias Systems Corp.
// 
// The information in this file is provided for the exclusive use of the
// licensees of Alias.  Such users have the right to use, modify,
// and incorporate this code into other products for purposes authorized
// by the Alias license agreement, without fee.
// 
// ALIAS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
// INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
// EVENT SHALL ALIAS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

//
//  Procedure Name:
//      renderLayerBuiltinPreset
//
//  Description:
//		Apply a built-in preset to a render layer node.
//
//  Input Arguments:
//      $name   - the name of the preset to apply.
//      $node   - the render layer node to apply the preset to.
//
//  Return Value:
//      None
//


proc string getLayerValuePlug(string $layer, string $scenePlug)
//
// Description:
//      Procedure to return the corresponding plug that holds a layer's
//      adjusted value. An empty string is returned if the plug is not
//      adjusted by the layer.
//
{
    // Find the adjustment if it exists
    string $plugs[] = `listConnections -p 1 $scenePlug`;
    for ($plug in $plugs) {
        if (plugNode($plug) == $layer) {
            if (`editRenderLayerGlobals -q -currentRenderLayer` == $layer) {
                return $scenePlug;
            }
            else {
                return substitute("\\.plug$", $plug, ".value");
            }
        }
    }
    // No adjustment
    return "";
}

proc string getLayerRenderer(string $layer)
//
// Description:
//      Procedure to return the name of the renderer used by a layer. An
//      empty string is returned if a renderer has not been set.
//
{
    string $renderer = "";
    string $plug = getLayerValuePlug($layer, "defaultRenderGlobals.currentRenderer");
    if ($plug != "") {
        $renderer = `getAttr $plug`;
    }
    return $renderer;
}

proc setLayerString(string $layer, string $scenePlug, string $value)
//
// Description:
//      Procedure to make a string adjustment to the specified plug.
//
{
    editRenderLayerAdjustment -layer $layer $scenePlug;
    string $plug = getLayerValuePlug($layer, $scenePlug);
    if ($plug != "") {
        setAttr -type "string" $plug $value;
    }
}

proc setLayerInt(string $layer, string $scenePlug, int $value)
//
// Description:
//      Procedure to make an integer adjustment to the specified plug.
//
{
    editRenderLayerAdjustment -layer $layer $scenePlug;
    string $plug = getLayerValuePlug($layer, $scenePlug);
    if ($plug != "") {
        setAttr $plug $value;
    }
}

proc setLayerFloat(string $layer, string $scenePlug, float $value)
//
// Description:
//      Procedure to make a float adjustment to the specified plug.
{
    editRenderLayerAdjustment -layer $layer $scenePlug;
    string $plug = getLayerValuePlug($layer, $scenePlug);
    if ($plug != "") {
        setAttr $plug $value;
    }
}

proc setLayerFloat3(string $layer, string $scenePlug, float $v1, float $v2, float $v3)
//
// Description:
//      Procedure to make a float3 adjustment to the specified plug.
{
    editRenderLayerAdjustment -layer $layer $scenePlug;
    string $plug = getLayerValuePlug($layer, $scenePlug);
    if ($plug != "") {
        setAttr $plug -type "float3" $v1 $v2 $v3;
    }
}

proc applyLinearDepth(string $node)
//
// Description:
//      Procedure to apply the built-in linear depth preset to a layer.
//
{
    // Set renderer
    string $renderer = getLayerRenderer($node);
    if ($renderer != "mayaSoftware") {
        // Set the renderer to Maya Software
        setLayerString($node, "defaultRenderGlobals.currentRenderer", "mayaSoftware");
    }

    // Set render globals
    setLayerInt($node, "defaultRenderGlobals.enableDefaultLight", off);
    setLayerInt($node, "defaultRenderQuality.edgeAntiAliasing", 0);
    
    // Shader override
    string $ifo = `shadingNode -asUtility samplerInfo`;
    string $mul = `shadingNode -asUtility multiplyDivide`;
    string $rng = `shadingNode -asUtility setRange`;
    string $sdr = `shadingNode -asShader surfaceShader`;
    string $set = `sets -renderable true -noSurfaceShader true -empty`;
    addAttr -longName "cameraNearClipPlane" -attributeType "float" $ifo;
    addAttr -longName "cameraFarClipPlane" -attributeType "float" $ifo;
    connectAttr ($ifo+".pointCameraZ") ($mul+".input1X");
    setAttr ($mul+".input2X") -1.0;
    connectAttr ($mul+".outputX") ($rng+".valueX");
    connectAttr ($ifo+".cameraNearClipPlane") ($rng+".oldMinX");
    connectAttr ($ifo+".cameraFarClipPlane") ($rng+".oldMaxX");
    setAttr ($rng+".minX") 1.0; // fcheck will scale to 200/255.
    setAttr ($rng+".maxX") 0.0;
    connectAttr ($rng+".outValueX") ($sdr+".outColorR");
    connectAttr ($rng+".outValueX") ($sdr+".outColorG");
    connectAttr ($rng+".outValueX") ($sdr+".outColorB");
    connectAttr ($sdr+".outColor") ($set+".surfaceShader");
    connectAttr -f ($set+".message") ($node+".shadingGroupOverride");
}

proc applyLogrithmicDepth(string $node)
//
// Description:
//      Procedure to apply the built-in logrithmic depth preset to a layer.
//
{
    // Set renderer
    string $renderer = getLayerRenderer($node);
    if ($renderer != "mayaSoftware") {
        setLayerString($node, "defaultRenderGlobals.currentRenderer", "mayaSoftware");
    }

    // Set render globals
    setLayerInt($node, "defaultRenderGlobals.enableDefaultLight", off);
    setLayerInt($node, "defaultRenderQuality.edgeAntiAliasing", 0);
    
    // Shader override
    string $ifo = `shadingNode -asUtility samplerInfo`;
    addAttr -longName "cameraNearClipPlane" -attributeType "float" $ifo;
    addAttr -longName "cameraFarClipPlane" -attributeType "float" $ifo;
    string $sdr = `shadingNode -asShader surfaceShader`;
    string $set = `sets -renderable true -noSurfaceShader true -empty`;
    string $script;
    $script += "float $zmin = "+$ifo+".cameraNearClipPlane;\n";
    $script += "float $zmax = "+$ifo+".cameraFarClipPlane;\n";
    $script += "float $ip = -("+$ifo+".pointCameraZ);\n";
    $script += "float $c = 0.0;\n";
    $script += "if ($zmin < $zmax && $ip >= $zmin && $ip <= $zmax) {\n";
    $script += "  float $zlogmax = log(1.0 + $zmax - $zmin);\n";
    $script += "  $c = log(1.0 + $ip - $zmin) / $zlogmax;\n";
    $script += "  $c = 1.0 - $c;\n";
    $script += "}\n";
    $script += $sdr+".outColorR = $c;\n";
    $script += $sdr+".outColorG = $c;\n";
    $script += $sdr+".outColorB = $c;\n";
    string $exp = `expression -string $script`;
    connectAttr ($sdr+".outColor") ($set+".surfaceShader");
    connectAttr -f ($set+".message") ($node+".shadingGroupOverride");
}

proc applyOcclusion(string $node)
//
// Description:
//      Procedure to apply the built-in occlusion preset to a layer.
//
{
    // Set renderer
    miLoadMayatomr();
    miCreateDefaultNodes();
    string $renderer = getLayerRenderer($node);
    if ($renderer != "mentalRay") {
        setLayerString($node, "defaultRenderGlobals.currentRenderer", "mentalRay");
    }
    
    // Set render globals
    setLayerInt($node, "defaultRenderGlobals.enableDefaultLight", off);
    setLayerInt($node, "miDefaultOptions.minSamples", 0);
    setLayerInt($node, "miDefaultOptions.maxSamples", 2);
    setLayerInt($node, "miDefaultOptions.filter", 1); // triangle
    setLayerFloat($node, "miDefaultOptions.filterWidth", 1.0);
    setLayerFloat($node, "miDefaultOptions.filterHeight", 1.0);
    setLayerFloat($node, "miDefaultOptions.contrastR", 0.02);
    setLayerFloat($node, "miDefaultOptions.contrastG", 0.02);
    setLayerFloat($node, "miDefaultOptions.contrastB", 0.02);
    setLayerFloat($node, "miDefaultOptions.contrastA", 0.02);
    setLayerInt($node, "miDefaultOptions.rayTracing", on);
    setLayerInt($node, "miDefaultOptions.maxReflectionRays", 1);
    setLayerInt($node, "miDefaultOptions.maxRefractionRays", 1);
    setLayerInt($node, "miDefaultOptions.maxRayDepth", 1);
    setLayerInt($node, "miDefaultOptions.maxShadowRayDepth", 2);
    
    // Camera background color
    string $cameras[] = `listCameras`;
    for ($camera in $cameras) {
        setLayerFloat3($node, ($camera+".backgroundColor"), 1.0, 1.0, 1.0);
    }

    // Create shader override
    string $tex = `mrCreateCustomNode -asTexture "" mib_amb_occlusion`;
    string $sdr = `shadingNode -asShader surfaceShader`;
    string $set = `sets -renderable true -noSurfaceShader true -empty`;
    connectAttr ($tex+".outValue") ($sdr+".outColor");
    connectAttr ($sdr+".outColor") ($set+".surfaceShader");
    connectAttr -f ($set+".message") ($node+".shadingGroupOverride");
}

proc applyMatte(string $node)
//
// Description:
//      Procedure to apply the built-in matte preset to a layer.
//
{
    // Set renderer
    string $renderer = getLayerRenderer($node);
    if ($renderer != "mayaSoftware" && $renderer != "mentalRay" && $renderer != "mayaHardware") {
        setLayerString($node, "defaultRenderGlobals.currentRenderer", "mayaSoftware");
    }

    // Set render globals
    setLayerInt($node, "defaultRenderGlobals.enableDefaultLight", off);
    setLayerInt($node, "defaultRenderQuality.edgeAntiAliasing", 0);
    
    // Shader override
    string $sdr = `shadingNode -asShader surfaceShader`;
    setAttr ($sdr+".outColor") -type float3 1.0 1.0 1.0;
    string $set = `sets -renderable true -noSurfaceShader true -empty`;
    connectAttr ($sdr+".outColor") ($set+".surfaceShader");
    connectAttr -f ($set+".message") ($node+".shadingGroupOverride");
}

proc applyDiffuse(string $node)
//
// Description:
//      Procedure to apply the built-in diffuse preset to a layer.
//
{
    // Set renderer
    string $renderer = getLayerRenderer($node);
    if ($renderer != "mayaSoftware" && $renderer != "mentalRay") {
        setLayerString($node, "defaultRenderGlobals.currentRenderer", "mayaSoftware");
    }

    // Set render globals
    setLayerInt($node, "defaultRenderQuality.enableRaytracing", off);
    if (`objExists "miDefaultOptions"`) {
        setLayerInt($node, "miDefaultOptions.rayTracing", off);
    }

    // Layer pass settings
    setAttr ($node+".beauty")   off;
    setAttr ($node+".color")    off;
    setAttr ($node+".shadow")   off;
    setAttr ($node+".diffuse")  on;
    setAttr ($node+".specular") off;
}

proc applySpecular(string $node)
//
// Description:
//      Procedure to apply the built-in specular preset to a layer.
//
{
    // Set renderer
    string $renderer = getLayerRenderer($node);
    if ($renderer != "mayaSoftware" && $renderer != "mentalRay") {
        setLayerString($node, "defaultRenderGlobals.currentRenderer", "mayaSoftware");
    }

    // Layer pass settings
    setAttr ($node+".beauty")   off;
    setAttr ($node+".color")    off;
    setAttr ($node+".shadow")   off;
    setAttr ($node+".diffuse")  off;
    setAttr ($node+".specular") on;
}

proc applyShadow(string $node)
//
// Description:
//      Procedure to apply the built-in shadow preset to a layer.
//
{
    // Set renderer
    string $renderer = getLayerRenderer($node);
    if ($renderer != "mayaSoftware" && $renderer != "mentalRay") {
        setLayerString($node, "defaultRenderGlobals.currentRenderer", "mayaSoftware");
    }

    // Layer pass settings
    setAttr ($node+".beauty")   off;
    setAttr ($node+".color")    off;
    setAttr ($node+".shadow")   on;
    setAttr ($node+".diffuse")  off;
    setAttr ($node+".specular") off;
}

global proc renderLayerBuiltinPreset(string $name, string $node)
{
    if ($name == "linearDepth") {
        applyLinearDepth($node);
    }
    else if ($name == "logrithmicDepth") {
        applyLogrithmicDepth($node);
    }
    else if ($name == "occlusion") {
        applyOcclusion($node);
    }
    else if ($name == "matte") {
        applyMatte($node);
    }
    else if ($name == "diffuse") {
        applyDiffuse($node);
    }
    else if ($name == "specular") {
        applySpecular($node);
    }
    else if ($name == "shadow") {
        applyShadow($node);
    }
    else {
        error("Unknown preset "+$name);
    }
}
