/*/////////////////////////////////////////////////////////////////
jpMayaToMia
author:
       Jon Parker
       [email protected]
       created May 4, 2008

usage:
       jpMayaToMia(<shader>)
       jpMayaToMia_selected()

return value:
       jpMayaToMia -> mia_material

description:
       converts a maya blinn, phong, phongE, lambert or anisotropic
       material to a mia_material shader. This does some rough
       guesswork on converting some of the parameters and is often
       not 100% visually identical to the original in its result.
/////////////////////////////////////////////////////////////////*/

// returns nodes of type "type" in input list
proc string[] jpFilterNodeType(string $type, string $inputList[])
{
       string $outputNodeList[];
       for ($input in $inputList)
       {
               string $inputType = `nodeType $input`;
               string $inputClass[] =`getClassification $inputType`;
               // do this to a type node
               if ($inputType == $type)
               {
                       $outputNodeList[size($outputNodeList)] = $input;
               }
               // do this to non-shader object
               else if ($inputType == "transform" || $inputType == "mesh" || $inputType == "nurbsSurface")
               {
                       string $shapeList[] = `listRelatives -ad -pa -type "surfaceShape" $input`;
                       $shapeList = stringArrayRemoveDuplicates($shapeList);
                       for ($shape in $shapeList)
                       {
                               string $sg[] = `listConnections -type "shadingEngine" $shape`;
                               if (($sg[0] != "initialShadingGroup") && (size($sg)))
                               {
                                       string $shadingNetwork[] = `listHistory -pdo 1 $sg[0]`;
                                       if (size($shadingNetwork))
                                       {
                                               for ($outputNode in $shadingNetwork)
                                               {
                                                       if (`nodeType $outputNode` == $type)
                                                       {
                                                               $outputNodeList[size($outputNodeList)] = $outputNode;
                                                       }
                                               }
                                       }
                               }
                       }
               }
               // ...or do this to a shader
               else
               {
                       string $shadingNetwork[] = `listHistory -pdo 1 $input`;
                       if (size($shadingNetwork))
                       {
                               for ($outputNode in $shadingNetwork)
                               {
                                       if (`nodeType $outputNode` == $type)
                                       {
                                               $outputNodeList[size($outputNodeList)] = $outputNode;
                                       }
                               }
                       }
               }
       }

       $outputNodeList = stringArrayRemoveDuplicates($outputNodeList);
       return $outputNodeList;
}

proc string createAndPrepareMia(string $shader)
{
       string $mia = `shadingNode -asShader -n ($shader+"_mia") mia_material_x`;
               setAttr ".brdf_0_degree_refl" 1;
               setAttr ".skip_inside_refl" 0;
               setAttr ".refr_ior" 1.0 ;
               setAttr ".brdf_conserve_energy" off ;
       warning ("createAndPrepareMia: "+$mia+": 'brdf conserve energy' is turned off for visual equality with the Maya shader.  You should turn this back on for better physical accuracy.");
       return $mia;
}

proc copyAttribute(string $src, string $dest)
{
       string $srcSplit[];
       tokenize $src "." $srcSplit;
       string $srcNode = $srcSplit[0];
       string $srcAttr = $srcSplit[1];
       string $srcScalar[] = `listAttr -s $src`;
//      print $srcScalar;

       string $destSplit[];
       tokenize $dest "." $destSplit;
       string $destNode = $destSplit[0];
       string $destAttr = $destSplit[1];
       string $destScalar[] = `listAttr -s $dest`;
//      print $destScalar;


       if (`attributeQuery -n $srcNode -uac $srcAttr` && `connectionInfo -id $src`)
       {
                       string $inputNode = `connectionInfo -sfd $src`;
                       connectAttr -f $inputNode $dest;
       }
       else
       {
               for ($i = 0; $i < size($srcScalar); $i++)
               {
                       if (`connectionInfo -id ($srcNode+"."+$srcScalar[$i])`)
                       {
                               string $inputNode = `connectionInfo -sfd ($srcNode+"."+$srcScalar[$i])`;
                               connectAttr -f $inputNode ($destNode+"."+$destScalar[$i]);
                       }
                       else
                       {
                               float $srcValue = `getAttr ($srcNode+"."+$srcScalar[$i])`;
                               setAttr ($destNode+"."+$destScalar[$i]) $srcValue;
                       }
               }
       }
}

global proc copyCommonAttributesToMiaMaterial(string $shader, string $mia)
{
       // color
       copyAttribute(($shader+".color"), ($mia+".diffuse"));

       // transparency
       // only set it up if we have transparency
       float $trans[] = `getAttr ($shader+".transparency")`;
       if ((`connectionInfo -id ($shader+".transparency")`) || ($trans[0] || $trans[1] || $trans[2] !=0))
       {
               print $trans;
               setAttr ($mia+".transparency") 1;
               copyAttribute(($shader+".transparency"), ($mia+".refr_color"));
       }

       // ambient color
       setAttr ($mia+".ao_on") true;
       setAttr ($mia+".ao_samples") 0;
       setAttr ($mia+".ao_distance") 0;
       setAttr ($mia+".ao_do_details") 0;
       setAttr ($mia+".ao_dark") -type double3 1 1 1;
       copyAttribute(($shader+".ambientColor"), ($mia+".ao_ambient"));

       // incandescence
       copyAttribute(($shader+".incandescence"), ($mia+".additional_color"));

       // bump mapping
       if (`connectionInfo -id ($shader+".normalCamera")`)
       {
               string $srcBump = `connectionInfo -sfd ($shader+".normalCamera")`;
               connectAttr -f $srcBump ($mia+".overall_bump");
       }

       // diffuse attr
       copyAttribute(($shader+".diffuse"), ($mia+".diffuse_weight"));

       // translucence
       if (`getAttr ($shader+".translucence")` != 0)
       {
               setAttr ($mia+".refr_translucency") on;
               copyAttribute(($shader+".color"), ($mia+".refr_trans_color"));
               copyAttribute(($shader+".translucence"), ($mia+".refr_trans_weight"));
               // multiply it by the transparency...
               if (`getAttr ($mia+".transparency")` != 0)
               {
                       // set translucency weight
                       string $rev = `shadingNode -asUtility -n ($mia+"_refr_trans_weight_rev") reverse`;
                       string $lum = `shadingNode -asUtility -n ($mia+"_refr_trans_weight_lum") luminance`;

                       copyAttribute(($mia+".refr_color"), ($rev+".input"));
                       connectAttr -f ($rev+".output") ($lum+".value");
                       connectAttr -f ($lum+".outValue") ($mia+".refr_trans_weight");

                       // set translucency color
                       string $mult = `shadingNode -asUtility -n ($mia+"_refr_color_mult") multiplyDivide`;

                       copyAttribute(($shader+".color"), ($mult+".input1"));
                       copyAttribute(($shader+".translucence"), ($mult+".input2X"));
                       copyAttribute(($shader+".translucence"), ($mult+".input2Y"));
                       copyAttribute(($shader+".translucence"), ($mult+".input2Z"));
                       connectAttr -f ($mult+".output") ($mia+".refr_trans_color");

                       // set transparency color
                       string $rgbIn = `shadingNode -asUtility -n ($mia+"_refr_color_rgbIn") rgbToHsv`;
                       string $setRange = `shadingNode -asUtility -n ($mia+"_refr_color_setRange") setRange`;
                               setAttr ".minZ" 1;
                               setAttr ".maxX" 1;
                               setAttr ".maxY" 1;
                               setAttr ".maxZ" 1;
                               setAttr ".oldMaxX" 1;
                               setAttr ".oldMaxY" 1;
                               setAttr ".oldMaxZ" 1;
                       string $rgbOut = `shadingNode -asUtility -n ($mia+"_refr_color_rgbOut") hsvToRgb`;

                       copyAttribute(($shader+".transparency"), ($rgbIn+".inRgb"));
                       connectAttr -f ($rgbIn+".outHsv") ($setRange+".value") ;
                       connectAttr -f ($setRange+".outValue") ($rgbOut+".inHsv") ;
                       connectAttr -f ($rgbOut+".outRgb") ($mia+".refr_color") ;
               }
               else
               {
                       copyAttribute(($shader+".translucence"), ($mia+".transparency"));
                       setAttr ($mia+".refr_trans_weight") 1;
               }
       }

       // raytracing
       if (`getAttr ($shader+".refractions")` == 1)
       {
               copyAttribute(($shader+".refractiveIndex"), ($mia+".refr_ior"));
               copyAttribute(($shader+".refractionLimit"), ($mia+".refr_depth"));
               if (`getAttr ($shader+".lightAbsorbance")` != 0)
               {
                       setAttr ($mia+".refr_falloff_on") true;
                       copyAttribute(($shader+".lightAbsorbance"), ($mia+".refr_falloff_dist"));
               }
       }

       // mental ray
       // irradiance
       if (`connectionInfo -id ($shader+".miIrradianceColor")`)
       {
               string $input = `connectionInfo -sfd ($shader+".miIrradianceColor")`;
               string $lumaNode = `shadingNode -asUtility luminance`;
               connectAttr -f $input ($lumaNode+".value") ;
               connectAttr -f ($lumaNode+".outValue") ($mia+".indirect_multiplier");
       }
       else
       {
               float $irrad[] = `getAttr ($shader+".miIrradianceColor")`;
               float $indMult = ($irrad[0]+$irrad[1]+$irrad[2])/3;
               setAttr ($mia+".indirect_multiplier") $indMult;
       }

       // refraction blur
       if (`connectionInfo -id ($shader+".miRefractionBlur")`)
       {
               string $input = `connectionInfo -sfd ($shader+".miRefractionBlur")`;
               string $mult = `shadingNode -asUtility -n ($mia+"_refr_gloss_mult") multiplyDivide`;
                       setAttr ".input2X" 0.1 ;
               string $rev = `shadingNode -asUtility -n ($mia+"_refr_gloss_rev") reverse`;
               connectAttr -f $input ($mult+".input1X");
               connectAttr -f ($mult+".outputX") ($rev+".inputX") ;
               connectAttr -f ($rev+".outputX") ($mia+".refr_gloss") ;
       }
       else
       {
               float $refrBlur = `getAttr ($shader+".miRefractionBlur")`;
               if ($refrBlur != 0) setAttr ($mia+".refr_gloss") (1-($refrBlur*.1)) ;
       }
}

proc copyLambertAttributesToMiaMaterial(string $shader, string $mia)
{
       setAttr ($mia+".reflectivity") 0;
}

proc copyPhongAttributesToMiaMaterial(string $shader, string $mia)
{
       if (`connectionInfo -id ($shader+".cosinePower")`)
       {
               string $input = `connectionInfo -sfd ($shader+".cosinePower")`;
               string $clamp = `shadingNode -asUtility -n ($mia+"_refl_gloss_clamp") clamp`;
                       setAttr ".maxR" 100 ;
               string $mult = `shadingNode -asUtility -n ($mia+"_refl_gloss_mult") multiplyDivide`;
                       setAttr ".input2X" 0.01 ;
               connectAttr -f $input ($clamp+".inputR") ;
               connectAttr -f ($clamp+".outputR") ($mult+".input1X") ;
               connectAttr -f ($mult+".outputX") ($mia+".refl_gloss") ;
       }
       else
       {
               float $cosine = `getAttr ($shader+".cosinePower")`;
               setAttr ($mia+".refl_gloss") (clamp(0, 100, $cosine)*.01);
       }

       copyAttribute(($shader+".specularColor"), ($mia+".refl_color")) ;
       copyAttribute(($shader+".reflectivity"), ($mia+".reflectivity")) ;
       copyAttribute(($shader+".reflectionLimit"), ($mia+".refl_depth")) ;
}

proc copyPhongEAttributesToMiaMaterial(string $shader, string $mia)
{
       warning "copyPhongEAttributesToMiaMaterial: certain phongE material settings are weird and unsupported... set the reflection glossiness in the mia material to approximate phongE specular attributes.";
       copyAttribute(($shader+".specularColor"), ($mia+".refl_color")) ;
       copyAttribute(($shader+".reflectivity"), ($mia+".reflectivity")) ;
       copyAttribute(($shader+".reflectionLimit"), ($mia+".refl_depth")) ;

}

proc copyBlinnAttributesToMiaMaterial(string $shader, string $mia)
{
       // figure out that inverse eccentricity thing... it's roughly worked out...
       if (`connectionInfo -id ($shader+".eccentricity")`)
       {
               string $input = `connectionInfo -sfd ($shader+".eccentricity")`;
               string $gamma = `shadingNode -asUtility -n ($mia+"_refl_gloss_gamma") gammaCorrect`;
                       setAttr ".gammaX" 2.718 ;
               string $rev = `shadingNode -asUtility -n ($mia+"_refl_gloss_rev") reverse`;

               connectAttr -f $input ($gamma+".valueX") ;
               connectAttr -f ($gamma+".outValueX") ($rev+".inputX") ;
               connectAttr -f ($rev+".outputX") ($mia+".refl_gloss") ;
       }
       else
       {
               float $ecc = `getAttr ($shader+".eccentricity")`;
               float $thinger = 1-((exp($ecc)-.5) * .5);
               setAttr ($mia+".refl_gloss") (1-((exp($ecc)-.5) * .5)) ;
       }

       // let's put the specular roll-off into the forward-facing reflectivity of the mia...
       copyAttribute(($shader+".specularRollOff"), ($mia+".brdf_0_degree_refl")) ;

       // do the standard specular stuff
       copyAttribute(($shader+".specularColor"), ($mia+".refl_color")) ;
       copyAttribute(($shader+".reflectivity"), ($mia+".reflectivity")) ;
       copyAttribute(($shader+".reflectionLimit"), ($mia+".refl_depth")) ;
}

proc copyAnisoAttributesToMiaMaterial(string $shader, string $mia)
{
       setAttr ($mia+".anisotropy_channel") -2 ;
       // get angle, see if it's mapped first
       if (`connectionInfo -id ($shader+".angle")`)
       {
               string $mult = `shadingNode -asUtility -n ($mia+"_anisotropy_rotation_mult") multiplyDivide`;
                       setAttr ".operation" 2 ;
                       setAttr ".input1Y" 720 ;
               copyAttribute(($shader+".angle"), ($mult+".input1X"));
               connectAttr -f ($mult+".outputX") ($mia+".anisotropy_rotation") ;
       }
       else
       {
               float $rotation = `getAttr ($shader+".angle")` / 720 ;
               setAttr ($mia+".anisotropy_rotation") $rotation ;
       }
       // divide the x and y aniso values to approximate the mia anisotropy
       if (`connectionInfo -id ($shader+".spreadX")` || `connectionInfo -id ($shader+".spreadY")`)
       {
               string $div = `shadingNode -asUtility -n ($mia+"_anisotropy_div") multiplyDivide`;
                       setAttr ".operation" 2 ;
               copyAttribute(($shader+".spreadY"), ($div+".input1X"));
               copyAttribute(($shader+".spreadX"), ($div+".input1Y"));
               connectAttr -f ($div+".outputX") ($mia+".anisotropy");
       }
       else
       {
               float $anisoValue = `getAttr ($shader+".spreadY")` / `getAttr ($shader+".spreadX")`;
               setAttr ($mia+".anisotropy") $anisoValue ;
       }
       // finally roughness
       if (`connectionInfo -id ($shader+".roughness")`)
       {
               string $inv = `shadingNode -asUtility -n ($mia+"_refl_gloss_inv") reverse`;
               copyAttribute ($shader+".roughness") ($inv+".inputX") ;
               connectAttr -f ($inv+".outputX") ($mia+".refl_gloss") ;
       }
       else
       {
               float $gloss = 1 - `getAttr ($shader+".roughness")` ;
               setAttr ($mia+".refl_gloss") $gloss ;
       }

       // figure out what to do with the anisotropic reflection attribute
       if (`getAttr ($shader+".anisotropicReflectivity")`)
               warning ("copyAnisoAttributesToMiaMaterial: "+$shader+": anisotropic reflectivity settings ignored.");

       copyAttribute(($shader+".specularColor"), ($mia+".refl_color")) ;
       copyAttribute(($shader+".reflectivity"), ($mia+".reflectivity")) ;
       copyAttribute(($shader+".reflectionLimit"), ($mia+".refl_depth")) ;
}

global proc string jpMayaToMia(string $shader)
{
       string $mia = createAndPrepareMia($shader);
       copyCommonAttributesToMiaMaterial($shader, $mia);
       if (`nodeType $shader` == "lambert") copyLambertAttributesToMiaMaterial($shader, $mia);
       if (`nodeType $shader` == "phong") copyPhongAttributesToMiaMaterial($shader, $mia);
       if (`nodeType $shader` == "phongE") copyPhongEAttributesToMiaMaterial($shader, $mia);
       if (`nodeType $shader` == "blinn") copyBlinnAttributesToMiaMaterial($shader, $mia);
       if (`nodeType $shader` == "anisotropic") copyAnisoAttributesToMiaMaterial($shader, $mia);

       return $mia;
}

global proc jpMayaToMia_selected()
{
       string $selection[] = `ls -sl`;
       string $shaderList[] ;
       string $lambertList[] = jpFilterNodeType("lambert", $selection) ;
       string $phongList[] = jpFilterNodeType("phong", $selection) ;
       string $phongEList[] = jpFilterNodeType("phongE", $selection);
       string $blinnList[] = jpFilterNodeType("blinn", $selection);
       string $anisoList[] = jpFilterNodeType("anisotropic", $selection);
       $shaderList = stringArrayCatenate($shaderList, $lambertList);
       $shaderList = stringArrayCatenate($shaderList, $phongList);
       $shaderList = stringArrayCatenate($shaderList, $phongEList);
       $shaderList = stringArrayCatenate($shaderList, $blinnList);
       $shaderList = stringArrayCatenate($shaderList, $anisoList);
//      print $shaderList ;
       for ($shader in $shaderList)
       {

               string $mia = jpMayaToMia($shader) ;
               string $sgList[] = `listConnections -type "shadingEngine" $shader`;
               for ($sg in $sgList)
               {
                       string $miaSG[] = `duplicate -ic -n ($mia + "SG") $sg` ;
                       string $shader = `connectionInfo -sfd ($miaSG[0]+".surfaceShader")`;
                       disconnectAttr $shader ($miaSG[0]+".surfaceShader") ;
                       connectAttr -f ($mia+".message") ($miaSG[0]+".miMaterialShader") ;
                       connectAttr -f ($mia+".message") ($miaSG[0]+".miPhotonShader") ;
                       connectAttr -f ($mia+".message") ($miaSG[0]+".miShadowShader") ;
                       string $assignedObjectList[] = `sets -q $sg`;
                       sets -e -fe $miaSG[0] $assignedObjectList ;
               }

       }
}