//PROC: Generate various shades of spheres and make gene shape
global proc createGene(int $total, int $aniAssembleStartPoint, float $aniTotalAssembleTime, int $mainSphereCnt, float $mainSphereSize, int $mainScatterCnt, 
    int $insideSphereCnt, int $insideScatterCnt, float $insideSphereSize, float $MscatterRange, float $IscatterRange) {
        string $curve_grp_name;
        
        //Get the main gene body shape (two curves)
        $curve_grp_name = generateGene();
        
        string $curvesName[] = `listRelatives -children $curve_grp_name`;
        string $wholeObjectNM = "myGene";
        string $curveSphereName[];
        string $curveSphereGrpNM = "curveSpheres";
        string $attr = $curvesName[0] + ".spans"; 
        int $spans = `getAttr $attr`;
        int $j;
        int $indivCnt = 0;
        int $curveSphTotalCnt = 0;
        
        float $randPosX;
        float $randPosY;
        float $randPosZ;
        int $mainSphereTotalCnt = $mainSphereCnt * $mainScatterCnt;
        float $mainAniFrameDegree = $aniTotalAssembleTime / (float)($mainSphereTotalCnt);        
        float $timeFrame = $aniAssembleStartPoint;
        
        //Generate spheres along with the curves
        for($curveNM in $curvesName){
            for($j=0; $j<$mainSphereCnt; $j++){
                string $attr = $curveNM + ".spans"; 
                int $spans = `getAttr $attr`;
                float $spanloc = (float)$spans * (float)$j / (float)$mainSphereCnt;
                vector $pntPos = `pointOnCurve -pr $spanloc -p $curveNM`;
                    
                int $h;
                float $scatterX;
                float $scatterY;
                float $scatterZ;
                for($h=0; $h<$mainScatterCnt; $h++){
                    float $range = $MscatterRange / 100;
                    $scatterX = rand(-$range, $range);
                    $scatterY = rand(-$range, $range);
                    $scatterZ = rand(-$range, $range);
                    
                    string $sphereNM = $curveNM + "_curveSph" + $indivCnt;
                    polySphere -n $sphereNM -r 1 -sx 20 -sy 20 -ax 0 1 0 -cuv 2 -ch 1;
                    $curveSphereName[$curveSphTotalCnt] = $sphereNM;
                    float $size = $mainSphereSize / 100;
                    scale -a $size $size $size;
                    setAnimation(0.0, $sphereNM);
                    
                    $randPosX = rand(-10, 10);
                    $randPosZ = rand(-10, 10);
                    move -a $randPosX ($pntPos.y + $scatterY) $randPosZ;
                    setAnimation(2.0, $sphereNM);
  
                    setAnimation($timeFrame, $sphereNM);
                                
                    move -a ($pntPos.x + $scatterX) ($pntPos.y + $scatterY) ($pntPos.z + $scatterZ);        
                    setAnimation(($timeFrame + ($mainAniFrameDegree * ($indivCnt+1))), $sphereNM);
                    
                    $indivCnt++;
                    $curveSphTotalCnt++;
                }
            }
            $indivCnt = 0;
        }
        
        groupObjects($curveSphereName, $curveSphereGrpNM);        
        
        $indivCnt = 0;
        $timeFrame = $aniAssembleStartPoint;
        int $insideSphereTotalCnt = ($total+1) * $insideSphereCnt * $insideScatterCnt;
        float $insideAniFrameDegree = $aniTotalAssembleTime / (float)($insideSphereTotalCnt);
        string $insideSphereName[];
        string $insideSphereGrpNM = "insideSpheres";
        
        //Generate spheres between curves
        for($j=0; $j<$total+1; $j++){
            string $curveNM = "curve" + ($j+2);
            vector $pnt1 = `pointOnCurve -pr ((float)$spans*(float)$j/(float)$total) -p $curvesName[0]`;
            vector $pnt2 = `pointOnCurve -pr ((float)$spans*(float)$j/(float)$total) -p $curvesName[1]`;
            float $angle = ($pnt2.z - $pnt1.z) / ($pnt2.x - $pnt1.x);
            float $pointZ = $pnt1.z - ($pnt1.x * $angle);
            
            int $i;
            float $degree = ($pnt2.x - $pnt1.x) / 10;
            
            for($i=0; $i < $insideSphereCnt; $i++){
                float $tempX = $pnt1.x + ($i * $degree);
                float $tempZ = ($angle * $tempX) + $pointZ;
                
                int $h;
                float $scatterX;
                float $scatterY;
                float $scatterZ;
                for($h=0; $h<$insideScatterCnt; $h++){
                    float $range = $IscatterRange / 100;
                    $scatterX = rand(-$range, $range);
                    $scatterZ = rand(-$range, $range);
  
                    string $sphereNM = "insideSph" + $indivCnt;                    
                    polySphere -n $sphereNM -r 1 -sx 20 -sy 20 -ax 0 1 0 -cuv 2 -ch 1;
                    $insideSphereName[$indivCnt] = $sphereNM;                    
                    float $size = $insideSphereSize / 100;
                    scale -a $size $size $size;
                    setAnimation(0.0, $sphereNM);
                    
                    $randPosX = rand(-10, 10);
                    $randPosZ = rand(-10, 10);
                    move -a $randPosX ($pnt1.y + $scatterY) $randPosZ;
                    setAnimation(2.0, $sphereNM);
  
                    setAnimation($timeFrame, $sphereNM);
                    
                    move -a ($tempX + $scatterX) ($pnt1.y + $scatterY) ($tempZ + $scatterZ);                    
            
                    setAnimation(($timeFrame + ($insideAniFrameDegree * ($indivCnt+1))), $sphereNM);
                        
                    $indivCnt++;
                }
            }    
        }
        
        groupObjects($insideSphereName, $insideSphereGrpNM);            
        delete $curve_grp_name;
        groupAll($curveSphereGrpNM, $insideSphereGrpNM, $wholeObjectNM);
}
  
//PROC: Generate two curves for main gene body shape
global proc string generateGene(){
    global string $curves[];
    
    string $gene = "gene";
    string $firstCurve = "curve0";
    string $secondCurve = "curve1";
    int $degree = 60;
    
    curve -n $firstCurve -d 3
    -p (sin(deg_to_rad($degree*-6))) -6 (cos(deg_to_rad($degree*-6)))
    -p (sin(deg_to_rad($degree*-5))) -5 (cos(deg_to_rad($degree*-5)))
    -p (sin(deg_to_rad($degree*-4))) -4 (cos(deg_to_rad($degree*-4)))
    -p (sin(deg_to_rad($degree*-3))) -3 (cos(deg_to_rad($degree*-3)))
    -p (sin(deg_to_rad($degree*-2))) -2 (cos(deg_to_rad($degree*-2)))
    -p (sin(deg_to_rad($degree*-1))) -1 (cos(deg_to_rad($degree*-1)))
    -p (sin(deg_to_rad($degree*0))) 0 (cos(deg_to_rad($degree*0)))
    -p (sin(deg_to_rad($degree*1))) 1 (cos(deg_to_rad($degree*1)))
    -p (sin(deg_to_rad($degree*2))) 2 (cos(deg_to_rad($degree*2)))
    -p (sin(deg_to_rad($degree*3))) 3 (cos(deg_to_rad($degree*3)))
    -p (sin(deg_to_rad($degree*4))) 4 (cos(deg_to_rad($degree*4)))
    -p (sin(deg_to_rad($degree*5))) 5 (cos(deg_to_rad($degree*5)))
    -p (sin(deg_to_rad($degree*6))) 6 (cos(deg_to_rad($degree*6)));
    
    duplicate -n $secondCurve $firstCurve;
    select $secondCurve;
    rotate -r 0 90 0;
    $curves[0] = $firstCurve;
    $curves[1] = $secondCurve;
    
    groupObjects($curves, $gene);
    clear $curves;
    return $gene;
}
  
//PROC: Group objects into one
global proc groupObjects(string $objNames[], string $groupName){
  
    select -r $objNames[0];
    int $i;
    for($i=1; $i<size($objNames); $i++){
        select -tgl $objNames[$i];    
    }
    group -n $groupName;
}
  
//PROC: Group two different groups into one
global proc groupAll(string $objName1, string $objName2, string $groupName){
  
    select -r $objName1;
    select -tgl $objName2;
    group -n $groupName;
}
  
//Setting the animation for each sphere.
global proc setAnimation(float $timeFrame, string $sphereNM){
  
    string $timeCmd = $timeFrame + "sec";
    setKeyframe -attribute "translateX" -t $timeCmd $sphereNM;
    setKeyframe -attribute "translateY" -t $timeCmd $sphereNM;
    setKeyframe -attribute "translateZ" -t $timeCmd $sphereNM;
    setKeyframe -attribute "rotateZ" -t $timeCmd $sphereNM;
    setKeyframe -attribute "rotateY" -t $timeCmd $sphereNM;
    setKeyframe -attribute "rotateX" -t $timeCmd $sphereNM;
}