//Dave Lewis
//VSFX160 Intro to VSFX Programming
//Spring 09

//Four Seasons Script

//This script will generate fields of "trees" for use as proxy objects in previz or for
/low-cost geometry in games. Four variations of a procedure make 4 versions of the tree
//object, a differing one for each "season".

//Each tree consists of 10 locators, a curve whose points match and are parented to the
//locators' positions, a circle, an extruded surface made from the circle and the curve,
//and a particle field parented to the top locator used to simulate the leaves. Because of
//the way the script builds each component, every tree and its characteristics are editable
//even after the script has finished. The procedures build each tree and parents its
//components under a larger locator that enables the group to be moved as a whole.

//Entering 'BuildBoxUI' in the command line will bring up the UI to adjust and run the code.


//Spring building procedure
proc buildSpring (int $iter) {
   //create locators and curve to match
   for ($i = 0; $i < 10; $i++) {
      $locXVal = "locator" + $i + ".tx";
      $locYVal = "locator" + $i + ".ty";
      $locZVal = "locator" + $i + ".tz";
      $curvePtXVal = "curveShape1" + ".controlPoints[" + $i + "].xValue";
      $curvePtYVal = "curveShape1" + ".controlPoints[" + $i + "].yValue";
      $curvePtZVal = "curveShape1" + ".controlPoints[" + $i + "].zValue";
      string $newCurve;

      spaceLocator -name ("locator" + $i) -p 0 0 0;

      if (`objExists locator1`) {
         move `rand -2 2` `rand ($i*2) (($i*2)+2)` `rand -2 2`;
      };

      if (`objExists curve1`) {
         curve -a -p (`getAttr $locXVal`) (`getAttr $locYVal`) (`getAttr $locZVal`) $newCurve;
      } else {
         $newCurve = `curve -p 0 0 0`;
      };

      connectAttr -f $locXVal $curvePtXVal;
      connectAttr -f $locYVal $curvePtYVal;
      connectAttr -f $locZVal $curvePtZVal;
   }

   //rename locators and curve
    rename curve1 ("compCurve" + $iter);
   for ($i = 0; $i < 10; $i++) {
      rename ("locator" + $i) ("comp" + $iter + "Locator" + $i);
   }

   //create circle and extrude
   circle -c 0 0 0 -nr 0 1 0 -d 3 -s 12 -ch 1 -n ("compCircle" + $iter);
   extrude -ch true -rn true -po 0 -rotation 0 -scale 0 -rsp 1 -n ("compExtrude" + $iter) ("compCircle" + $iter) ("compCurve" + $iter);

   //create particle and expression and link them to the end locator
   string $particleName = "compParticle" + $iter;
   string $expString = $particleName + "Shape.rgbPP = <<`rand 0.4 1`, 0, `rand .3 .8`>>;\n" +
   $particleName + "Shape.radius = .1";

   particle -jbp 0 0 0 -nj 600 -jr 7 -c 1 -n $particleName;
   connectAttr -f ("comp" + $iter + "Locator9.translateX") ($particleName + ".translateX");
   connectAttr -f ("comp" + $iter + "Locator9.translateY") ($particleName + ".translateY");
   connectAttr -f ("comp" + $iter + "Locator9.translateZ") ($particleName + ".translateZ");
   setAttr ($particleName + "Shape.particleRenderType") 4;
   addAttr -is true -ln "radius" -at "float" -min 0 -max 10 -dv 0.5 ($particleName + "Shape");
   addAttr -ln "rgbPP" -dt vectorArray ($particleName + "Shape");
   addAttr -ln "rgbPP0" -dt vectorArray ($particleName + "Shape");
   dynExpression -s $expString -c ($particleName + "Shape");

   //create overall locator for entire group
   spaceLocator -n ("overLocator" + $iter);
   setAttr ("overLocator" + $iter + "Shape.localScaleX") 5;
   setAttr ("overLocator" + $iter + "Shape.localScaleY") 5;
   setAttr ("overLocator" + $iter + "Shape.localScaleZ") 5;

   //select components
   select ("compCurve" + $iter) ("compCircle" + $iter) ("compExtrude" + $iter) $particleName;
   for ($i = 0; $i < 10; $i++) {
      select -add ("comp" + $iter + "Locator" + $i);
   }

   //parent components under overall locator
   group -n ("compGroup" + $iter) -p ("overLocator" + $iter);
   }

//Summer building procedure
proc buildSummer (int $iter) {
   //create locators and curve to match
   for ($i = 0; $i < 10; $i++) {
      $locXVal = "locator" + $i + ".tx";
      $locYVal = "locator" + $i + ".ty";
      $locZVal = "locator" + $i + ".tz";
      $curvePtXVal = "curveShape1" + ".controlPoints[" + $i + "].xValue";
      $curvePtYVal = "curveShape1" + ".controlPoints[" + $i + "].yValue";
      $curvePtZVal = "curveShape1" + ".controlPoints[" + $i + "].zValue";
      string $newCurve;

      spaceLocator -name ("locator" + $i) -p 0 0 0;

      if (`objExists locator1`) {
         move `rand -2 2` `rand ($i*2) (($i*2)+2)` `rand -2 2`;
      };

      if (`objExists curve1`) {
         curve -a -p (`getAttr $locXVal`) (`getAttr $locYVal`) (`getAttr $locZVal`) $newCurve;
      } else {
         $newCurve = `curve -p 0 0 0`;
      };

      connectAttr -f $locXVal $curvePtXVal;
      connectAttr -f $locYVal $curvePtYVal;
      connectAttr -f $locZVal $curvePtZVal;
   }

   //rename locators and curve
   rename curve1 ("compCurve" + $iter);
   for ($i = 0; $i < 10; $i++) {
      rename ("locator" + $i) ("comp" + $iter + "Locator" + $i);
   }

   //create circle and extrude
   circle -c 0 0 0 -nr 0 1 0 -d 3 -s 12 -ch 1 -n ("compCircle" + $iter);
   extrude -ch true -rn true -po 0 -rotation 0 -scale 0 -rsp 1 -n ("compExtrude" + $iter) ("compCircle" + $iter) ("compCurve" + $iter);

   //create particle and expression and link them to the end locator
   string $particleName = "compParticle" + $iter;
   string $exprString = $particleName + "Shape.rgbPP = <<0, `rand 0.4 1`, 0 >>;\n"
      + $particleName + "Shape.spriteTwist = `rand -180 180`";

   particle -jbp 0 0 0 -nj 700 -jr 7 -c 1 -n $particleName;
   connectAttr -f ("comp" + $iter + "Locator9.translateX") ($particleName + ".translateX");
   connectAttr -f ("comp" + $iter + "Locator9.translateY") ($particleName + ".translateY");
   connectAttr -f ("comp" + $iter + "Locator9.translateZ") ($particleName + ".translateZ");
   setAttr ($particleName + ".particleRenderType") 5;
   setAttr ($particleName + "Shape.depthSort") 1;
   addAttr -is true -ln "spriteTwist" -at "float" -min -180 -max 180 -dv 0.0 ($particleName + "Shape");
   addAttr -is true -ln "spriteScaleX" -dv .5 ($particleName + "Shape");
   addAttr -is true -ln "spriteScaleY" -dv .5 ($particleName + "Shape");
   addAttr -is true -ln "spriteNum" -at long -dv 1 $particleName;
   addAttr -is true -ln "useLighting" -at bool -dv false $particleName;
   addAttr -ln "rgbPP" -dt vectorArray ($particleName + "Shape");
   addAttr -ln "rgbPP0" -dt vectorArray ($particleName + "Shape");
   dynExpression -s $exprString -c ($particleName + "Shape");

   //create overall locator for entire group
   spaceLocator -n ("overLocator" + $iter);
   setAttr ("overLocator" + $iter + "Shape.localScaleX") 5;
   setAttr ("overLocator" + $iter + "Shape.localScaleY") 5;
   setAttr ("overLocator" + $iter + "Shape.localScaleZ") 5;

   //select components
   select ("compCurve" + $iter) ("compCircle" + $iter) ("compExtrude" + $iter) $particleName;
   for ($i = 0; $i < 10; $i++) {
      select -add ("comp" + $iter + "Locator" + $i);
   }

   //parent components under overall locator
   group -n ("compGroup" + $iter) -p ("overLocator" + $iter);
};

//Fall building procedure
proc buildFall (int $iter) {
   //create locators and curve to match
   for ($i = 0; $i < 10; $i++) {
      $locXVal = "locator" + $i + ".tx";
      $locYVal = "locator" + $i + ".ty";
      $locZVal = "locator" + $i + ".tz";
      $curvePtXVal = "curveShape1" + ".controlPoints[" + $i + "].xValue";
      $curvePtYVal = "curveShape1" + ".controlPoints[" + $i + "].yValue";
      $curvePtZVal = "curveShape1" + ".controlPoints[" + $i + "].zValue";
      string $newCurve;

      spaceLocator -name ("locator" + $i) -p 0 0 0;

      if (`objExists locator1`) {
         move `rand -2 2` `rand ($i*2) (($i*2)+2)` `rand -2 2`;
      };

      if (`objExists curve1`) {
         curve -a -p (`getAttr $locXVal`) (`getAttr $locYVal`) (`getAttr $locZVal`) $newCurve;
      } else {
         $newCurve = `curve -p 0 0 0`;
      };

      connectAttr -f $locXVal $curvePtXVal;
      connectAttr -f $locYVal $curvePtYVal;
      connectAttr -f $locZVal $curvePtZVal;
   }

   //rename locators and curve
   rename curve1 ("compCurve" + $iter);
   for ($i = 0; $i < 10; $i++) {
      rename ("locator" + $i) ("comp" + $iter + "Locator" + $i);
   }

   //create circle and extrude
   circle -c 0 0 0 -nr 0 1 0 -d 3 -s 12 -ch 1 -n ("compCircle" + $iter);
   extrude -ch true -rn true -po 0 -rotation 0 -scale 0 -rsp 1 -n ("compExtrude" + $iter) ("compCircle" + $iter) ("compCurve" + $iter);

   //create particle and expression and link them to the end locator
   string $particleName = "compParticle" + $iter;
   string $grdParticleName = "compGrdParticle" + $iter;
   string $expString = $particleName + "Shape.rgbPP = <<`rand 0.4 1`, `rand .3 .8`, 0>>;\n"
      + $particleName + "Shape.spriteTwist = `rand -180 180`";
   string $expGrdString = $grdParticleName + "Shape.rgbPP = <<`rand .2 .7`, `rand .1 .5`, 0>>;\n"
      + $grdParticleName + "Shape.spriteTwist = `rand -180 180`";

   particle -jbp 0 0 0 -nj 400 -jr 7 -c 1 -n $particleName;
   connectAttr -f ("comp" + $iter + "Locator9.translateX") ($particleName + ".translateX");
   connectAttr -f ("comp" + $iter + "Locator9.translateY") ($particleName + ".translateY");
   connectAttr -f ("comp" + $iter + "Locator9.translateZ") ($particleName + ".translateZ");
   setAttr ($particleName + "Shape.particleRenderType") 5;
   setAttr ($particleName + "Shape.depthSort") 1;
   addAttr -is true -ln "spriteTwist" -at "float" -min -180 -max 180 -dv 0.0 ($particleName + "Shape");
   addAttr -is true -ln "spriteScaleX" -dv .5 ($particleName + "Shape");
   addAttr -is true -ln "spriteScaleY" -dv .5 ($particleName + "Shape");
   addAttr -is true -ln "spriteNum" -at long -dv 1 $particleName;
   addAttr -is true -ln "useLighting" -at bool -dv false $particleName;
   addAttr -ln "rgbPP" -dt vectorArray ($particleName + "Shape");
   addAttr -ln "rgbPP0" -dt vectorArray ($particleName + "Shape");
   dynExpression -s $expString -c ($particleName + "Shape");

   particle -jbp 0 0 0 -nj 100 -jr 7 -c 1 -n $grdParticleName;
   connectAttr -f ("comp" + $iter + "Locator0.translateX") ($grdParticleName + ".translateX");
   connectAttr -f ("comp" + $iter + "Locator0.translateY") ($grdParticleName + ".translateY");
   connectAttr -f ("comp" + $iter + "Locator0.translateZ") ($grdParticleName + ".translateZ");
   setAttr ($grdParticleName + ".scaleY") 0;
   setAttr ($grdParticleName + "Shape.particleRenderType") 5;
   addAttr -is true -ln "spriteTwist" -at "float" -min -180 -max 180 -dv 0.0 ($grdParticleName + "Shape");
   addAttr -is true -ln "spriteScaleX" -dv .5 ($grdParticleName + "Shape");
   addAttr -is true -ln "spriteScaleY" -dv .5 ($grdParticleName + "Shape");
   addAttr -is true -ln "spriteNum" -at long -dv 1 $grdParticleName;
   addAttr -is true -ln "useLighting" -at bool -dv false $grdParticleName;
   addAttr -ln "rgbPP" -dt vectorArray ($grdParticleName + "Shape");
   addAttr -ln "rgbPP0" -dt vectorArray ($grdParticleName + "Shape");
   dynExpression -s $expGrdString -c ($grdParticleName + "Shape");

   //create overall locator for entire group
   spaceLocator -n ("overLocator" + $iter);
   setAttr ("overLocator" + $iter + "Shape.localScaleX") 5;
   setAttr ("overLocator" + $iter + "Shape.localScaleY") 5;
   setAttr ("overLocator" + $iter + "Shape.localScaleZ") 5;

   //select components
   select ("compCurve" + $iter) ("compCircle" + $iter) ("compExtrude" + $iter) $particleName $grdParticleName;
   for ($i = 0; $i < 10; $i++) {
      select -add ("comp" + $iter + "Locator" + $i);
   }

   //parent components under overall locator
   group -n ("compGroup" + $iter) -p ("overLocator" + $iter);
}

//Winter building procedure
proc buildWinter (int $iter) {
   //create locators and curve to match
   for ($i = 0; $i < 10; $i++) {
      $locXVal = "locator" + $i + ".tx";
      $locYVal = "locator" + $i + ".ty";
      $locZVal = "locator" + $i + ".tz";
      $curvePtXVal = "curveShape1" + ".controlPoints[" + $i + "].xValue";
      $curvePtYVal = "curveShape1" + ".controlPoints[" + $i + "].yValue";
      $curvePtZVal = "curveShape1" + ".controlPoints[" + $i + "].zValue";
      string $newCurve;

      spaceLocator -name ("locator" + $i) -p 0 0 0;

      if (`objExists locator1`) {
         move `rand -2 2` `rand ($i*2) (($i*2)+2)` `rand -2 2`;
      };

      if (`objExists curve1`) {
         curve -a -p (`getAttr $locXVal`) (`getAttr $locYVal`) (`getAttr $locZVal`) $newCurve;
      } else {
         $newCurve = `curve -p 0 0 0`;
      };

      connectAttr -f $locXVal $curvePtXVal;
      connectAttr -f $locYVal $curvePtYVal;
      connectAttr -f $locZVal $curvePtZVal;
   }

   //rename locators and curve
   rename curve1 ("compCurve" + $iter);
   for ($i = 0; $i < 10; $i++) {
      rename ("locator" + $i) ("comp" + $iter + "Locator" + $i);
   }

   //create circle and extrude
   circle -c 0 0 0 -nr 0 1 0 -d 3 -s 12 -ch 1 -n ("compCircle" + $iter);
   extrude -ch true -rn true -po 0 -rotation 0 -scale 0 -rsp 1 -n ("compExtrude" + $iter) ("compCircle" + $iter) ("compCurve" + $iter);

   //create overall locator for entire group
   spaceLocator -n ("overLocator" + $iter);
   setAttr ("overLocator" + $iter + "Shape.localScaleX") 5;
   setAttr ("overLocator" + $iter + "Shape.localScaleY") 5;
   setAttr ("overLocator" + $iter + "Shape.localScaleZ") 5;

   //select components
   select ("compCurve" + $iter) ("compCircle" + $iter) ("compExtrude" + $iter);
   for ($i = 0; $i < 10; $i++) {
      select -add ("comp" + $iter + "Locator" + $i);
   }

   //parent components under overall locator
   group -n ("compGroup" + $iter) -p ("overLocator" + $iter);
};
 
//Field building procedure, calls specific season procedures based on user input
proc buildField (int $buildType, int $buildNum, int $xSpread, int $zSpread) {
   if ($buildType == 1) {
      currentTime 1;
      for ($i = 1; $i < ($buildNum + 1); $i++) {
         buildSpring($i);
         select ("overLocator" + $i);
         move `rand ($xSpread * -1) $xSpread` 0 `rand ($zSpread * -1) $zSpread`;
         $randScale = `rand .5 1`;
         setAttr ("overLocator" + $i + ".scaleX") $randScale;
         setAttr ("overLocator" + $i + ".scaleY") $randScale;
         setAttr ("overLocator" + $i + ".scaleZ") $randScale;
      };
      print "Build Spring";
   } else if ($buildType == 2) {
      currentTime 1;
      for ($i = 1; $i < ($buildNum + 1); $i++) {
         buildSummer($i);
         select ("overLocator" + $i);
         move `rand ($xSpread * -1) $xSpread` 0 `rand ($zSpread * -1) $zSpread`;
         $randScale = `rand .5 1`;
         setAttr ("overLocator" + $i + ".scaleX") $randScale;
         setAttr ("overLocator" + $i + ".scaleY") $randScale;
         setAttr ("overLocator" + $i + ".scaleZ") $randScale;
      };
      print "Build Summer";
   } else if ($buildType == 3) {
      currentTime 1;
      for ($i = 1; $i < ($buildNum + 1); $i++) {
      buildFall($i);
         select ("overLocator" + $i);
         move `rand ($xSpread * -1) $xSpread` 0 `rand ($zSpread * -1) $zSpread`;
         $randScale = `rand .5 1`;
         setAttr ("overLocator" + $i + ".scaleX") $randScale;
         setAttr ("overLocator" + $i + ".scaleY") $randScale;
         setAttr ("overLocator" + $i + ".scaleZ") $randScale;
      };
      print "Build Fall";
   } else if ($buildType == 4) {
      currentTime 1;
      for ($i = 1; $i < ($buildNum + 1); $i++) {
         buildWinter($i);
         select ("overLocator" + $i);
         move `rand ($xSpread * -1) $xSpread` 0 `rand ($zSpread * -1) $zSpread`;
         $randScale = `rand .5 1`;
         setAttr ("overLocator" + $i + ".scaleX") $randScale;
         setAttr ("overLocator" + $i + ".scaleY") $randScale;
         setAttr ("overLocator" + $i + ".scaleZ") $randScale;
      };
      print "Build Winter";
   };
   select -cl;
}

//procedure to build the UI
global proc buildBoxUI() {
   if(`window -exists buildBox`){
      deleteUI buildBox;
   }
   if(`windowPref -exists buildBox`){
      windowPref -remove buildBox;
   }

   global string $countSlider;
   global string $spreadXSlider;
   global string $spreadZSlider;
   global int $buildType = 3;

   window -title "8-bit Tree Generator" -rtf true buildBox;
   columnLayout;
   $countSlider = `intSliderGrp -cat 1 left 0 -min 1 -fmn 1 -max 200 -value 10 -label "Tree Count" -field true countSlider`;
   $spreadXSlider = `floatSliderGrp -cat 1 left 0 -pre 2 -min 5 -fmn 5 -max 50 -fmx 50 -value 10 -label "Field X-Spread" -field true spreadXSlider`;
   $spreadZSlider = `floatSliderGrp -cat 1 left 0 -pre 2 -min 5 -fmn 5 -max 50 -fmx 50 -value 10 -label "Field Z-Spread" -field true spreadZSlider`;
   setParent..;
   columnLayout;
   radioButtonGrp -cal 1 left -nrb 4 -label "Season" -labelArray4 "Spring" "Summer" "Fall" "Winter"
   -on1 "$buildType = 1" -on2 "$buildType = 2" -on3 "$buildType = 3" -on4 "$buildType = 4";
   setParent..;
   rowColumnLayout -nc 1;
   button -label "Build Field" -command "buildField($buildType, `intSliderGrp -q -value $countSlider`, `floatSliderGrp -q -value $spreadXSlider`, `floatSliderGrp -q -value $spreadZSlider`)";
   showWindow;
};