// 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.

//
//  Alias Script File
//  MODIFY THIS AT YOUR OWN RISK
//
//  Creation Date:  2003
//
// Description: Create hairs on selected objects 
//	

global proc createHair(int $uCount, int $vCount, int $numCvs, int $restCurves, int $passiveFill, int $edgeBounded, int $equalize, float $length, float $randomization, int $outputMode, int $simulationType, int $hairCreateType)
{
	// TODO change to hair license??
	if( !fluidEditLicenseFound() ) {	
		error( "Fluid license not found." );
		return;
	}
	if(!`optionVar -exists createHairMaxDensity`){
		optionVar -intValue createHairMaxDensity 100;
	}
	int $maxDensity = `optionVar -query createHairMaxDensity`;
	int $doOutputCurve = $outputMode > 1;
	int $doPfxHair = $outputMode == 1 || $outputMode == 3;
	
	int $largeNumberOfCurves = 1000;
	// The following trys to gage the relative effect of large number of cvs on performance 
	int $largeNumberOfHairs  = 10000.0/(1.0 + ((float)$numCvs * .05)); 
	
	string $potentialTargets[];
	string $targets[];
	int $maxHairs;
	int $numTargets;
	
	if($hairCreateType == 1) {  //Grid hairs
		$potentialTargets = `ls -sl -dag`;
		$targets = `ls -sl -dag -ni -type nurbsSurface -type mesh`;
		$numTargets = size($targets);
		if( $numTargets < 1 ){
			if( size ($potentialTargets) < 1)
				warning( "No objects selected for hair creation" );
			else
				warning( "Hair can only be created on NURBS or polygon surfaces" );
			return;
		}
		$maxHairs = $uCount * $vCount * $numTargets;
	}
	else if($hairCreateType == 2) {   // Hair at selected surface points/faces
		string $allObjects[] = `ls -sl`;
		for($obj in $allObjects) {
			string $parts[];
			tokenize( $obj,".[]",$parts );
			if ( `nodeType $parts[0]` == "transform" ) {
				string $kids[] = `listRelatives -f -children $parts[0]`;
				int $i;
				for ( $i=0; $i<size($kids); $i++ ) {
					if ( `nodeType $kids[$i]` == "nurbsSurface" ) {
						if(!`getAttr ($kids[$i]+".io")`) {
							string $nurbsParts[];
							tokenize( $obj,"[]",$nurbsParts );
							if( size($nurbsParts) == 3 )							
								$targets[size($targets)] = $obj;
						}
					}
					else if ( `nodeType $kids[$i]` == "mesh" )	{
						if(!`getAttr ($kids[$i]+".io")`) {																				
							string $polyParts[];
							tokenize( $obj,":[]",$polyParts );
							if( size($polyParts) == 3 )	{
								int $count;
								for($count = int($polyParts[1]); $count<=int($polyParts[2]); $count++)
									$targets[size($targets)] = $polyParts[0] + "[" + $count + "]" ;									
							}
							else if( size($polyParts) == 2 ) {								
								$targets[size($targets)] = $obj;
							}														
						}
					}
				}
			}
		}
		$numTargets = size($targets);
		if( $numTargets < 1 ){
			if( size ($allObjects) < 1)
				warning( "No objects selected for hair creation" );
			else
				warning( "Hair can only be created on selected surface point(s)/face(s)" );
			return;
		}
		$maxHairs = $numTargets;
	}
	
	int $hideOutputCurves = false;
	if( $doOutputCurve && $maxHairs > $largeNumberOfCurves ){
		string $retString = `confirmDialog -title "Create Hair Confirm" 
		-message ("Ok to generate "+$maxHairs+" hairs?\n"
				 +"This may result in slow system performance.\n"
				 +"Output nurbs curves are much slower to update than pfxHair nodes.\n"
				 +"You can choose to initially hide the output curves group yet have them\n"
				 +"display using a pfxHair node, which will update faster.")
    	-button "Create Hair Curves" -button "Create and Hide Hair Curves" -button "Cancel" -defaultButton "Cancel"
    	-cancelButton "Cancel" -dismissString "Cancel"`;

		if( $retString == "Cancel" ){
			return;
		}else if( $retString == "Create and Hide Hair Curves" ){
			$hideOutputCurves = true;
		}
	} else if( $maxHairs > $largeNumberOfHairs ){
		string $warnStr =  "Ok to generate "+$maxHairs+" hair clumps?\n";
		if( $maxHairs > $largeNumberOfHairs * 10 ){
			 $warnStr +=("This number of hairs is greater than most systems can currently handle.\n"
						+"It is advisable to backup current scene before attempting this.");
		} else {
			 $warnStr +="This may result in very slow system performance.";
		}
		string $retString = `confirmDialog -title "Create Hair Confirm" 
		-message $warnStr
    	-button "Create Hair" -button "Cancel" -defaultButton "Cancel"
    	-cancelButton "Cancel" -dismissString "Cancel"`;
		if( $retString != "Create Hair" ){
			return;
		}
	}
	int $uhairs;
	int $vhairs;

	if($hairCreateType == 1) { //Grid
		if( $uCount > $maxDensity || $vCount > $maxDensity ){
			int $uvMax;
			if( $uCount > $vCount ){
				$uvMax = $uCount;
			} else {
				$uvMax = $vCount;
			}
			string $retString = `confirmDialog -title "Create Hair Confirm" 
			-message ("The requested U or V count exceeds the current hair naming grid size.\n"
					+"This is controlled by the option variable \"createHairMaxDensity\"\n" 
					+"You can reset this variable to the new value of " + $uvMax +" by selecting \"Create Paintable hair\".\n"
					+"Note that changing this variable will affect using the hair paint tool\n"
					+"with previously created hair systems. It can also make painting slower.\n")
    		-button "Create Hair" -button "Create Paintable Hair" -button "Cancel" -defaultButton "Cancel"
    		-cancelButton "Cancel" -dismissString "Cancel"`;
			if( $retString == "Create Paintable Hair" ){
				optionVar -intValue createHairMaxDensity $uvMax;	
				$maxDensity = $uvMax;
			} else if( $retString == "Create Hair" ){
				$maxDensity = $uvMax;	
			} else if( $retString == "Cancel" ){
				return;
			}	
		}
	/*
		int $uhairs = sqrt( $numHairs );
		int $vhairs = $uhairs;
	*/
		$uhairs = $uCount;
		$vhairs = $vCount;

		if( $uhairs < 2 || $vhairs < 2 ){
			if( $uhairs < 1 || $vhairs < 1 ){
				return;
			}
			$equalize = false;
		}
	}
	
	// Get hair system from hair system menu
	string $hsys;
	int		$placeIn;
	int     $newHairSys = false;
	if(`optionMenuGrp -q -ex hsPlaceMenu`) {
		$placeIn = `optionMenuGrp -q -select hsPlaceMenu`;
		if ( $placeIn == 1 ) {
			$hsys = `createNode hairSystem`;
			connectAttr time1.outTime ($hsys + ".currentTime");
			$newHairSys = true;
		} else {
			$hsys = `optionMenuGrp -q -value hsPlaceMenu`;
			if( $doPfxHair ){
				string $con[] = `listConnections ($hsys + ".outputRenderHairs")`;
				if( size($con) > 0 ){
					$doPfxHair = false;
				}
			}
			$newHairSys = false;
		}
	}
	else {
		string $hairSystems[] = `ls -sl -dag -ni -type hairSystem`;		
		if( size( $hairSystems ) > 0 ){
			$hsys = $hairSystems[0];
			if( $doPfxHair ){
				string $con[] = `listConnections ($hsys + ".outputRenderHairs")`;
				if( size($con) > 0 ){
					$doPfxHair = false;
				}
			}
			$newHairSys = false;
		} else {
			$hsys = `createNode hairSystem`;
			connectAttr time1.outTime ($hsys + ".currentTime");
			$newHairSys = true;
		}
	}		

	string $hsysGroup  = "";
	string $hsysOutHairGroup = "";
	string $hsysParent[] = `listTransforms $hsys`;
	if( size($hsysParent) > 0  ){
		$hsysGroup = $hsysParent[0] + "Follicles";
		if( !objExists( $hsysGroup ) ){
			$hsysGroup = `group -em -name $hsysGroup`;
		}
		if( $doOutputCurve ){
			$hsysOutHairGroup = ($hsysParent[0] + "OutputCurves");
			if( !objExists( $hsysOutHairGroup ) ){
				$hsysOutHairGroup = `group -em -name $hsysOutHairGroup`;
			}
			if( $hideOutputCurves ){
				setAttr ($hsysOutHairGroup + ".visibility")  false;
			}
		}
	}
	
	int $coincidentHairs = false;
	int $createdHairs = false;	
	if($hairCreateType == 1) { //Grid
		int $i, $ui, $ji;
		int $currentHair = 0;
		float $minU = 0.5/(float)$uhairs;
		float $minV = 0.5/(float)$vhairs;
		float $uDists[];
		float $vDists[];
		int	  $uSamples[];
		int	  $vSamples[];
		int   $lastIndex[] = {0};
		int $numDistTests = 4;	
		for( $i = 0; $i < $numTargets; $i++ ){
			string $target = $targets[$i];
			int $doEqualize = $equalize;
			string $parent[] = `listRelatives -p $target`;
			string $hairCurveNamePrefix = $parent[0] + "Follicle";

			// compute rough worldspace distances for each row
			float $maxV = 0;
			float $minV = 1000000;
			float $maxU = 0;
			float $minU = 1000000;
			float $pu, $pv;
			int $ubased = true;
			if( $doEqualize ){
				// create a temporary follicle for point on surface evaluation
				string $follicle = `createNode follicle`;
				connectAttr ($target + ".worldMatrix[0]") ($follicle + ".inputWorldMatrix");
				string $nType = `nodeType $target`;
				if( "nurbsSurface" == $nType ){ 
					connectAttr ($target + ".local") ($follicle + ".inputSurface");
				} else if( "mesh" == $nType ){
					connectAttr ($target + ".outMesh") ($follicle + ".inputMesh");
					string $currentUVSet[] = `polyUVSet -q -currentUVSet $target`;
					setAttr ($follicle + ".mapSetName") -type "string" $currentUVSet[0];
				}

				for( $ui = 0; $ui < $uhairs; $ui++ ){
					if( $edgeBounded && $uhairs > 1){
						$pu =(float)$ui/(float)($uhairs-1);
					} else {
						$pu = ((float)$ui+0.5)/(float)$uhairs;
					}
					// new code uses a follicle node rather than pointOnSurface
	//				float $lastPos[] = `pointOnSurface -top 1 -u $pu -v 0 -position $target`;
					float $lastPos[];
					int $numValidPoints = 0;
					float $dist = 0;
					setAttr ($follicle + ".parameterU") $pu;
					int $try = 0;
					int $testCount = $numDistTests;
					// we may need to sample more than $numDistTest points for
					// polysets where some uvs are not defined in regions, like the poles
					// of a sphere.
					while ( $try < 3 && $numValidPoints < 2 ){
						$numValidPoints = 0;
						for( $vi=0;$vi < $testCount; $vi++ ){
							$pv = (float)$vi/(float)$testCount;
							setAttr ($follicle + ".parameterV") $pv;
							if( getAttr( $follicle + ".validUv" )){
								float $pos[] = getAttr ($follicle + ".outTranslate");
		//						float $pos[] = `pointOnSurface -top 1 -u $pu -v $pv -position $target`;
			
								if( $numValidPoints > 0 ){
									float $x = $pos[0] - $lastPos[0];
									float $y = $pos[1] - $lastPos[1];
									float $z = $pos[2] - $lastPos[2];
									$dist += sqrt( $x*$x + $y*$y + $z*$z );
								}
								$lastPos = $pos;
								$numValidPoints++;
							}
						}
						$try++;
						$testCount *= 2;
					}
					if( $try > 1 && $numValidPoints > 1 ){
						$numValidPoints = $numValidPoints/$try;	
						if( $numValidPoints < 2 ){
							$numValidPoints = 2;
						}
					}
		
					if( $dist > $maxV ){
						$maxV = $dist;
					}
					if( $dist < $minV ){
						$minV = $dist;
					}
					$vDists[$ui] = $dist;
					$vSamples[$ui] = $numValidPoints;
				}
				for( $vi = 0; $vi < $vhairs; $vi++ ){
					if( $edgeBounded && $vhairs > 1){
						$pv =(float)$vi/(float)($vhairs-1);
					} else {
						$pv = ((float)$vi+0.5)/(float)$vhairs;
					}
					// float $lastPos[] = `pointOnSurface -top 1 -u 0 -v $pv -position $target`;
					float $lastPos[];
					int $numValidPoints = 0;
					float $dist = 0;
					setAttr ($follicle + ".parameterV") $pv;
					int $try = 0;
					int $testCount = $numDistTests;
					while ( $try < 3 && $numValidPoints < 2 ){
						$numValidPoints = 0;
						for( $ui=0;$ui < $testCount; $ui++ ){
							$pu = (float)$ui/(float)$testCount;
							setAttr ($follicle + ".parameterU") $pu;
							if( getAttr( $follicle + ".validUv" )){
								float $pos[] = getAttr ($follicle + ".outTranslate");
								//float $pos[] = `pointOnSurface -top 1 -u $pu -v $pv -position $target`;
								if( $numValidPoints > 0 ){
									float $x = $pos[0] - $lastPos[0];
									float $y = $pos[1] - $lastPos[1];
									float $z = $pos[2] - $lastPos[2];
									$dist += sqrt( $x*$x + $y*$y + $z*$z );
								}
								$lastPos = $pos;
								$numValidPoints++;
							}
						}
						$try++;
						$testCount *= 2;
					}
					if( $try > 1 && $numValidPoints > 1 ){
						$numValidPoints = $numValidPoints/$try;	
						if( $numValidPoints < 2 ){
							$numValidPoints = 2;
						}
					}
					if( $dist > $maxU ){
						$maxU = $dist;
					}
					if( $dist < $minU ){
						$minU = $dist;
					}
					$uDists[$vi] = $dist;
					$uSamples[$vi] = $numValidPoints;
				}
				// find out which direction is more variable:
				if( $minU == 0 ){
					$ubased = false;
				} else if( $minV == 0 ){
					$ubased = true;
				} else {
					$ubased = (float)$maxU/(float)$minU < (float)$maxV/(float)$minV;
				}
	/*
				if( $maxV < $maxU ){
					$vHairs = ($vHairs*$maxV)/$maxU;
				} else {
					$uHairs = ($uHairs*$maxU)/$maxV;
				}
	*/
				// delete temporary follicle
				string $tforms[] = `listTransforms $follicle`;
				delete $tforms[0];
				
			}
			int $xi, $yi, $xsize, $ysize;
			if( $ubased ){
				$xsize = $uhairs;
			} else {
				$xsize = $vhairs;
			}
			for( $xi = 0; $xi < $xsize; $xi++ ){
				int $passiveI = ($xi%($passiveFill+1)) && $xi != ($xsize-1);
				if( $ubased ){
					if( $doEqualize && $vSamples[$xi] > 1 ){
						$ysize = ((float)$numDistTests/(float)$vSamples[$xi]) * (float)$vhairs*$vDists[$xi]/$maxV;
						if( $ysize > $vhairs ){
							$ysize = $vhairs;
						}
					} else {
						$ysize = $vhairs;
					}
				} else {
					$ysize = $uhairs;
					if( $doEqualize && $uSamples[$xi] > 1 ){
						$ysize = ((float)$numDistTests/(float)$uSamples[$xi]) *(float)$uhairs*$uDists[$xi]/$maxU;
						if( $ysize > $uhairs ){
							$ysize = $uhairs;
						}
					} else {
						$ysize = $uhairs;
					}
				}
				for( $yi = 0; $yi < $ysize; $yi++ ){
					int $isPassive = $passiveI || ($yi%($passiveFill+1) && $yi != ($ysize-1));

					// float $rval = `rand 1`;
					if( $edgeBounded ){
						if( $ubased ){
							if( $xsize > 1 ){
								$pu =(float)$xi/(float)($xsize-1);
							} else {
								$pu = ((float)$xi + 0.5)/(float)$xsize;
							}
							if( $ysize > 1 ){
								$pv =(float)$yi/(float)($ysize-1);
							} else {
								$pv = ((float)$yi + 0.5)/(float)$ysize;
							}
						} else {
							if( $xsize > 1 ){
								$pv =(float)$xi/(float)($xsize-1);
							} else {
								$pv = ((float)$xi + 0.5)/(float)$xsize;
							}
							if( $ysize > 1 ){
								$pu =(float)$yi/(float)($ysize-1);
							} else {
								$pu = ((float)$yi + 0.5)/(float)$ysize;
							}
						}
					} else {
						if( $ubased ){
							$pu = ((float)$xi + 0.5)/(float)$xsize;
							$pv = ((float)$yi + 0.5)/(float)$ysize;
						} else {
							$pv = ((float)$xi + 0.5)/(float)$xsize;
							$pu = ((float)$yi + 0.5)/(float)$ysize;
						}
					}
					if( $randomization > 0 ){
						float $uRand = rand(1.0);	
						float $vRand = rand(1.0);	
						$pu += ($uRand - 0.5) * $randomization/(float)$uhairs;
						$pv += ($vRand - 0.5)* $randomization/(float)$vhairs;
		
						if( $pu < 0 ){
							$pu += 1.0;
						} else if( $pu > 1.0 ){
							$pu -= 1.0;
						}
						if( $pv < 0 ){
							$pv += 1.0;
						} else if( $pv > 1.0 ){
							$pv -= 1.0;
						}
					}
					// The hairCurve is named based on the object and the UV index
					// This allows the script hairCurvePaint to function on the resulting nodes.
					int $namingIndex = $maxDensity * (int)($pu * (float)($maxDensity-1) + 0.5)  + (int)($pv * (float)($maxDensity-1) +0.5);
					string $newName = $hairCurveNamePrefix + $namingIndex;
					int $doStart = !$isPassive;
					// int $doStart = true;
					int $createFollicle = true;
					if ( `objExists $newName` ) {
						// Note when a follicle exists we do not overwrite it. 
						// The name signifies the position and thus we allow subsequent
						// create hair calls with different uv density to insert new hairs between
						// existing ones. Thus this case is not an error.

						$createFollicle = false;
						if( nodeType( $newName ) == "transform" ){
							string $shapes[] = `ls -s -dag $newName`;
							// If the transform is empty it is likely left over from an incomplete hairSystem deletion 
							// We delete it so that we can create a new one.
							if( 0 == size($shapes) ){
								delete $newName;
								$createFollicle = true;
								warning( "Create hair: prior name conflict, deleting empty transform " + $newName );
							}
						}	
						if( !$createFollicle ){
							$coincidentHairs = true;
						}
					}
					if ( $createFollicle ) {
						string $newHair = 
							createHairCurveNode( $hsys, $target, 
								$pu, $pv, $numCvs, $doOutputCurve, 
								$doStart, $restCurves, $isPassive, 
								"", $length, $lastIndex, 
							        $hsysGroup, $hsysOutHairGroup, $simulationType);
						if( $newHair != "" ){
							// rename $newHair $newName;
							string $hname = `rename $newHair $newName`;
							if ( $hname != $newName ) {
								catch (error ("Hair Follicle name failed: wanted " + $newName + " got " + $hname));
							}
						}
						$createdHairs = true;
					}
					$currentHair++;
				}
			}
		}
	}
	else if($hairCreateType == 2) {	// Hair at selected surface points/faces
		int $i;
		int $currentHair = 0;
		int   $lastIndex[] = {0};		
		for( $i = 0; $i < $numTargets; $i++ )
		{
			string $parent[];			
			float $pu, $pv;
			string $parts[];
			string $surface;
			int $selectedSurfacePt=false;
			string $target = $targets[$i];
			tokenize( $target,".[]",$parts );			
			
			if ( `nodeType $parts[0]` == "transform" )	{
				string $kids[] = `listRelatives -f -children $parts[0]`;
				int $j;
				for ( $j=0; $j<size($kids); $j++ )	{
					if ( `nodeType $kids[$j]` == "nurbsSurface" ) {
						if(!`getAttr ($kids[$j]+".io")`) {
							tokenize( $target,"[]",$parts );
							$surface = $kids[$j];
							$parent = `listRelatives -p $surface`;
							$selectedSurfacePt = true;
							
							float $minU = `getAttr ($surface+".mnu")`;
							float $maxU = `getAttr ($surface+".mxu")`;
							float $minV = `getAttr ($surface+".mnv")`;
							float $maxV = `getAttr ($surface+".mxv")`;
							$pu = $parts[1];
							$pv = $parts[2];
							if( $maxU-$minU > 0.0 )														
								$pu = ($pu - $minU) /($maxU-$minU);
							else
								$pu = 0.0;
								
							if( $maxV-$minV > 0.0 )
								$pv = ($pv - $minV) /($maxV-$minV);
							else
								$pv = 0.0;							
						}
					}
					else if( `nodeType $kids[$j]` == "mesh" ) {
						if(!`getAttr ($kids[$j]+".io")` && $parts[1] == "f") {
							$surface = $kids[$j];
							$parent = `listRelatives -p $surface`;
							
							// If it has multiple UVs...
							string $UVs[];
							$UVs = `polyListComponentConversion -tuv $target`;
							if (size($UVs) != 0) {
								select -r $target;
								float $UVbbox[] = `polyEvaluate -bc2`;							
								$pu = (($UVbbox[0]+$UVbbox[1])/2.0) + 1e-5;
								$pv = (($UVbbox[2]+$UVbbox[3])/2.0) + 1e-5;
								if($pu < 0.0 || $pu > 1.0 || $pv < 0.0 || $pv > 1.0) {
									continue;
								}
								else{
									$selectedSurfacePt = true;
								}
							}							
							else {
								continue;
							}				
						}
					}
				}
			}
			if(!$selectedSurfacePt) 
				continue;

			string $hairCurveNamePrefix = $parent[0] + "Follicle";
			int $namingIndex = $maxDensity * (int)($pu * (float)($maxDensity-1) + 0.5)  + (int)($pv * (float)($maxDensity-1) +0.5);
			string $newName = $hairCurveNamePrefix + $namingIndex;
			int $doStart = true;
			int $createFollicle = true;
			if ( `objExists $newName` ) {
				// Note when a follicle exists we do not overwrite it. 
				// The name signifies the position and thus we allow subsequent
				// create hair calls with different uv density to insert new hairs between
				// existing ones. Thus this case is not an error.

				$createFollicle = false;
				if( nodeType( $newName ) == "transform" ){
					string $shapes[] = `ls -s -dag $newName`;
					// If the transform is empty it is likely left over from an incomplete hairSystem deletion 
					// We delete it so that we can create a new one.
					if( 0 == size($shapes) ){
						delete $newName;
						$createFollicle = true;
						warning( "Create hair: prior name conflict, deleting empty transform " + $newName );
					}
				}	
				if( !$createFollicle ){
					$coincidentHairs = true;
				}
			}			
			if ( $createFollicle ) {
				string $newHair = 
					createHairCurveNode( $hsys, $surface, 
						$pu, $pv, $numCvs, $doOutputCurve, 
						$doStart, $restCurves, false, 
						"", $length, $lastIndex, 
						$hsysGroup, $hsysOutHairGroup, $simulationType);
				if( $newHair != "" ){
					// rename $newHair $newName;
					string $hname = `rename $newHair $newName`;
					if ( $hname != $newName ) {
						catch (error ("Hair Follicle name failed: wanted " + $newName + " got " + $hname));
					}
				}
				$createdHairs = true;
			}
			$currentHair++;			
		}
	}
	if( $doPfxHair || $hideOutputCurves){
		string $pfxHair = `createNode pfxHair`;
		setAttr ( $pfxHair + ".displayPercent") 100;
		setAttr ( $pfxHair + ".drawAsMesh") false;
		if( !$doPfxHair ){
			setAttr ( $hsys + ".hairsPerClump") 1;
			setAttr ( $hsys + ".clumpWidth") 0;
		}
		connectAttr ($hsys + ".outputRenderHairs") ($pfxHair + ".renderHairs");
	}
	if($newHairSys == false && $outputMode > 1) {
		if(`pluginInfo -q -l Fur`)
			HfAddCurvesToFur($hsys);
	}
	
	select -r $hsys;
	displayHairCurves( "current", true );
	if( $coincidentHairs ){
		if( !$createdHairs ){
			warning( "createHair: follicles currently exist at all create locations, no new hairs created" );
		} else {
			print( "createHair: some hairs not created due to pre-existing follicles at identical positions\n" );
		}
	} else if( !$createdHairs ){
		warning( "createHair: no hairs created" );
	}
}
