--"Auto IK Stretch Script" written by Tyson Ibele based on the original
--script controller by Michael Comet (comet-cartoons.com)

try(destroydialog autoIKRollout)catch()

global lowerleg
global endbone
global ikchainpoint
global IKscript
global distance1
global numbones1
global parentbones = #()


rollout autoIKrollout "Auto IK Stretch"
(
	button autoik "Make the chain stretchy!" width:150 height:30
	checkbox check1 "Allow negative stretch" align:#center
	button noik "Remove Stretch" width:150 height:30
	label line1 "-------" align:#center
	label label0 ""
	label label1 "Select an Ik Chain point and click the buttons"
	label label2 "above to make the chain stretchy, or to remove"
	label label25 "previously-applied stretch!"
	label label3 " "
	label label6 "All questions, comments and suggestions can "
	label label7 "be emailed to tyson@tysonibele.com"
	hyperlink tysonEmail "www.tysonibele.com" color:blue hovercolor:red address:"http://www.tysonibele.com" align:#center
	
	on autoik pressed do
	(
		for b in 1 to selection.count do
		(
			max create mode
			if selection != undefined then
			(
				ikchainpoint = selection[b]
				endbone = ikchainpoint.controller.endjoint
				startjoint = ikchainpoint.controller.endjoint
				
				parentbones[1] = endbone
				parentbones.count = 1
				count = 1
				while startjoint != ikchainpoint.controller.startjoint do
				(
					
					parentbones[count+1] = parentbones[count].parent
					count += 1
					startjoint = startjoint.parent			
				)
				
						
				if endbone != undefined and ikchainpoint != undefined then
				(
					in coordsys world distance1 = (distance ikchainpoint.pos parentbones[1].pos)
					
					chainCA = attributes chain
					(
						parameters main rollout:params
						(
							stretchval type:#float ui:sval
							checkval type:#boolean ui:chval
							smoothcheck type:#boolean ui:cval
							smoothmult type:#float ui:mval
							posval type:#point3 animatable:true
						)
						
						rollout params "Extra Stretch Parameters"
						(
							spinner sval "Stretch Value: " type:#float range:[-400,400,0]
							checkbox chval "Allow negative stretch" type:#boolean align:#center
							label label1 "----"
							checkbox cval "Enable Smooth Stretch" 
							spinner mval "Smoothness: " type:#float range:[0,2.5,1]
						)
					)
					try(custattributes.delete ikchainpoint 1)catch()
					custAttributes.add ikchainpoint chainCA
					
					obj1= Point()
					obj1.name = "stretchHelper_" + obj1.name
					obj1.transform = ikchainpoint.transform
					obj1.parent = ikchainpoint
					obj1.scale = [.001,.001,.001]
					selection[b].posval.controller = point3_script()
					selection[b].posval.controller.addNode "helper_point" obj1
					selection[b].posval.controller.script = 
					"(in coordsys world(helper_point.parent.pos))"
					selection[b].smoothcheck = true
					selection[b].smoothmult = 1
					if check1.checked == true then selection[b].checkval = true else selection[b].checkval = false
	
					for k in 1 to (parentbones.count - 1) do
					(
						global f = 2
						parentbones[k].position.controller=Position_XYZ()
						parentbones[k].position.controller=position_list()
						parentbones[k].position.controller.available.controller = position_xyz()
						parentbones[k].position.controller[f].controller.x_position.controller=float_script()
	
						
					)
												
					for m in 1 to (parentbones.count - 1) do
					(
						in coordsys world distance1 = distance1 + (distance parentbones[m] parentbones[m+1]) 			
					
					)
					initScale = abs(parentbones[parentbones.count].scale[1])
			
			
					IKscript = "try(in coordsys world (	d = distance topLevelBone.pos ikChainPoint1)
								
								scale1 = abs(topLevelBone.scale[1])
								distance1 *= scale1/initscale
								st = (d - distance1)
								
								if checkval != true then
								(
									if (st < 0) then st = 0 							
								)
								
								if smoothcheck == true and checkval != true then
								(
															
									value = -(abs(distance1 - d)/distance1) - .5
									value *= 5 
									mult = 2.7 / (smoothmult)
									if mult < 1 then mult = 1
									amount2 = (1/(sqrt(3.14 )))*(mult)^-(((value)^2)/2)
									amount2 *= (distance1/3) * 2
								
								)else amount2 = 0
								
								amount2 = abs(amount2)
								
								amount = ((st  + amount2 + stretchval)/count1)
								
								(orig1 + amount/scale1))catch()"
			
					
					for q in 1 to (parentbones.count - 1) do
					(
					parentbones[q].position.controller[f].controller.x_position.controller.addnode "topLevelBone" ikchainpoint.controller.startJoint			
					parentbones[q].position.controller[f].controller.x_position.controller.addTarget "ikChainPoint1" ikchainpoint.posval.controller
					parentbones[q].position.controller[f].controller.x_position.controller.addconstant "distance1" distance1
					parentbones[q].position.controller[f].controller.x_position.controller.addconstant "orig1" (parentbones[q].position.controller[f].controller.x_position.controller.script as float)
					parentbones[q].position.controller[f].controller.x_position.controller.addconstant "count1" ((parentbones.count - 1) as integer)
					parentbones[q].position.controller[f].controller.x_position.controller.addconstant "initScale" initScale
					parentbones[q].position.controller[f].controller.x_position.controller.addTarget "stretchval" ikchainpoint.baseObject.chain[1]
					parentbones[q].position.controller[f].controller.x_position.controller.addTarget "checkval" ikchainpoint.baseObject.chain[2]
					parentbones[q].position.controller[f].controller.x_position.controller.addTarget "smoothcheck" ikchainpoint.baseObject.chain[3]
					parentbones[q].position.controller[f].controller.x_position.controller.addTarget "smoothmult" ikchainpoint.baseObject.chain[4]
				
					parentbones[q].position.controller[f].controller.x_position.controller.script = IKscript
					max create mode	
					)					
					)
							
			)
		)
	)
	
		on noik pressed do
		(
			for p in 1 to selection.count do
			(
			
				obj = selection[p].controller.endjoint
				try(selection[p].posval.controller = bezier_point3())catch()
				for j in 1 to 100 do
				(
					
						try(orig1 = obj.position.controller[1][1].controller.getconstant "orig1")catch()
						obj.position.controller=bezier_position()
						obj.position.controller=position_xyz()	
						try(in coordsys obj.parent (obj.position.x = orig1))catch()
						orig1 = undefined
						obj = obj.parent	
					
					if obj == selection[p].controller.startjoint then exit
				)
			
			try(delete (selection[p].posval.controller.getNode "helper_point"))catch()
			--try(custattributes.delete selection[p] 1)catch()
			selection[p].pos = selection[p].pos
			)
		)

)
createdialog autoIKrollout 230 270 350 300

