 // cgBreakdownPlugin
// Initial code generated by XSI SDK Wizard
// Executed Wed Mar 7 18:13:47 UTC+1100 2007 by 3d
// 
// based on tweenMachine for maya 

function XSILoadPlugin( in_reg )
{
	in_reg.Author = "chrisg";
	in_reg.Name = "cgBreakdownPlugin";
	in_reg.Email = "chrisg@chris-g.net";
	in_reg.URL = "http://www.chris-g.net";
	in_reg.Major = 1;
	in_reg.Minor = 33;

	in_reg.RegisterCommand("cgBreakdownSetup","cgBreakdownSetup");
	in_reg.RegisterCommand("cgBreakdown","cgBreakdown");
	in_reg.RegisterMenu(siMenuMCPAnimationID,"cgBreakdown_Menu",false,false);
	//RegistrationInsertionPoint - do not remove this line
 
	return true;
}

function XSIUnloadPlugin( in_reg )
{
	var strPluginName;
	strPluginName = in_reg.Name;
	return true;
}

function cgBreakdown_Init( ctxt )
{
	var oCmd;
	oCmd = ctxt.Source;
	oCmd.Description = "Makes breakdown keys";
	oCmd.ReturnValue = true;
	
	
   // Get the ArgumentCollection
   var oArgs;
   oArgs = oCmd.Arguments;
   oArgs.Add( "blendAmount", siArgumentInput, 0.5, siFloat  );
   oArgs.Add( "debug", siArgumentInput, false, siBool  );

	return true;
}

function cgBreakdownSetup_Execute(  )
{
	var opts = buildOptions();
	InspectObj( opts, "", "breakdown", siLock ); 

	return true;
}

function cgBreakdown_Execute( inBlend, inDebug ) {
	var debug = inDebug;
	var useQuatRots = true;
	
//	var fc = getValue("PlayControl.Current");
	var oPlayControl = ActiveProject.Properties.Item("Play Control");
	var fc = Math.round(oPlayControl.Parameters.Item("Current").Value);
	
	if (debug) {logmessage("currentFrame: " + fc );}
	try {
		var markingList = new VBArray( GetMarking() ).toArray();
	} catch(e) {
		var markingList = new Array();
	}
	
	SelectChildNodes(null, null, null); 
	
	for (var x=0; x<selection.count; x++) {
		var thisObj = selection(x);
		if (thisObj.families == "3D Objects") {
			var animP = thisObj.nodeAnimatedParameters( siFCurveSource, true)


			for (i=0; i<animP.count; i++) {
				var thisParam = animP(i);
				var breakdownParam = false;
				if (className(thisParam) != "ProxyParameter") {
					if (markingList.length > 0) {
						if (thisParam.marked == true ) {
							breakdownParam = true;
						}
					} else {
						breakdownParam = true;
					}
				}
				
				// check for locked params
				// params not locked by refmodels
				if (debug) {logmessage("lock type: " +  thisParam.lockType );}
				if (debug) {logmessage("lock level: " +  thisParam.lockLevel );}

				if (thisParam.lockType != 3) {
				if (thisParam.lockLevel != 0) {
					if (debug) {logmessage("Ignoring locked param: " + thisParam );}
					breakdownParam = false;
				}
				}
				
				
				if (breakdownParam == true) {
					var pSrc = thisParam.source;
					var pSn = thisParam.ScriptName;
					
					if (debug) {logmessage("parameter: " + thisParam );}
					if (debug) {logmessage("p source: " + className(pSrc));}
					if (className(pSrc) == "Mixer") {
						// animation layer - ignore it.
						logMessage("Can't handle animation layer on " + thisParam + " - skipping!");
						break;
					}
					
					if (pSrc.getNumKeys() > 0) {
						// only if fcurve has keys on it
					
						if (pSrc.keyExists(fc,0)) {
							var prevKeyIdx = (pSrc.GetNumKeys(pSrc.GetKeyFrame (0), (fc-1)) - 1);
							var nextKeyIdx = prevKeyIdx + 2;
						} else {
							var prevKeyIdx = (pSrc.GetNumKeys(pSrc.GetKeyFrame (0), fc) - 1);
							var nextKeyIdx = prevKeyIdx + 1;
						}
				
						if (prevKeyIdx == -1) {
							prevKeyIdx = 0; 
						}
						if (debug) {logmessage("\tprevKeyIdx = " + prevKeyIdx + "  / nextkeyidx=" + nextKeyIdx);}
				
						var prevKeyVal = pSrc.GetKeyValue(prevKeyIdx);
	
						if ((nextKeyIdx) < pSrc.Keys.Count ) {
							var nextKeyVal = pSrc.GetKeyValue(nextKeyIdx);
		
						} else {
							var nextKeyVal = prevKeyVal;
						}
	
						var valueDelta = (nextKeyVal - prevKeyVal);
						if (debug) {logmessage("\tdelta: " + valueDelta);}
	
						var newVal = prevKeyVal + (valueDelta * inBlend);
						if (debug) {logmessage("\tnew value = " + newVal);}
	
						// handling for quat rotation blending
						if (pSn  == "rotx" | pSn == "roty" | pSn == "rotz") { 
							// it's a rotation!
							if (useQuatRots == true) {
								//var prevRot = XSIMath.CreateVector3();
								//var nextRot = XSIMath.CreateVector3();
								
								//var newRot = quatSlerp(prevRot, nextRot, inBlend);
								//logmessage(newRot.y);
							}
						}
	
	
	
	
						// new key
						if (pSrc.keyExists(fc,0)) {
							//pSrc.RemoveKeys(fc, fc, true);
							if (debug) {logmessage("\tkey exists at frame " + fc);}
							var thisKey = pSrc.getKey(fc);
							thisKey.value = newVal;
						} else {
							if (debug) {logmessage("\tcreating new key at frame " + fc);}
							try {
								pSrc.addKey(fc, newVal, -1, false);
							} catch(e) {
								logmessage(e);
							}
						}
					}

				}
			}
		}
	}

	return true;
}


function quatSlerp(inRotPrev, inRotNext, inSlerpAmnt) {
	// converts two euler rotations to quats, slerps the two and eulers the result
	// expects and returns a siVector3 object
	var qA = XSIMath.CreateQuaternion();
	qA.SetFromXYZAngleValues( 
		XSIMath.DegreesToRadians(inRotPrev.x),
		XSIMath.DegreesToRadians(inRotPrev.y),
		XSIMath.DegreesToRadians(inRotPrev.z) );
	var qB = XSIMath.CreateQuaternion();
	qB.SetFromXYZAngleValues( 
		XSIMath.DegreesToRadians(inRotNext.x),
		XSIMath.DegreesToRadians(inRotNext.y),
		XSIMath.DegreesToRadians(inRotNext.z) );
		
	var qC = XSIMath.CreateQuaternion();
	qC.Slerp( qA, qB, inSlerpAmnt);

	var aXYZ = new VBArray(qC.GetXYZAngleValues2()).toArray();
	var ret = XSIMath.CreateVector3();
	ret.x = XSIMath.RadiansToDegrees(aXYZ[0]);
	ret.y = XSIMath.RadiansToDegrees(aXYZ[1]);
	ret.z =XSIMath.RadiansToDegrees(aXYZ[2]);
	
	
	return(ret);
}



function cgBreakdown_Menu_Init( ctxt )
{
	var oMenu;
	oMenu = ctxt.Source;
	oMenu.AddCommandItem("cgBreakdown","cgBreakdownSetup");
	return true;
}

function buildOptions( ) {
	if (findObj("cgBreakdown") == false) {
		var propObj = activeSceneRoot.AddProperty("CustomProperty",false, "cgBreakdown");
		
		propObj.AddParameter2("blendAmount", siFloat, 0, -1, 1) ;
		propObj.AddParameter2("debug", siBool, false) ;
		
		var instrString = "Creates a breakdown between the " + 
				"previous and next keys, based on the weight specified in the slider." + 
				"It operates on selected objects and if parameters are marked for keying " + 
				"(eg, the translate handle is active), it only creates keys on those marked parameters\r\n\r\n" +
				"Set the blend amount:\r\n" +
				"-1=fully weighted to previous key\r\n" +
				"0=equal weighting with prev and next keys\r\n" +
				"1=fully weighted to next key\r\n\r\n" +
				"Scripting: you can call cgBreakdown via scripts (for insane overshoot values)\r\n" +
				"Usage: cgBreakdown(blendAmount (float), debug (boolean));\r\n" +
				"";
		
		propObj.AddParameter2( "instructions", siString, instrString);
		
		var creditString = "Chris Gardner - 2007\r\n" +
				"http://www.chris-g.net\r\n\r\n" +
				"v1 - 08.03.07 - initial release\r\n" +
				"v1.1 - fixed bug where script was writing a key over the previous keyframe\r\n" +	
				"v1.2 - operates on branch selections\r\n" +
				"v1.21 - ignores animation layers cleanly\r\n" +
				"v1.3 - 21.10.08 - NEW: overshoot\r\n" +
				"v1.31 - 14.1.09 - FIX: cleanly ignores fcurves without any keys\r\n" +
				"v1.32 - 11.10.09 - FIX: Ignores locked params\r\n" +
				"v1.33 - 26.01.10 - FIX: Copes with param locks on refmodels\r\n" +
				//"\tNew: Interpolate rotations as quaternions\r\n" +
				"\r\n" +
				"Based on tweenMachine for Maya by Justin Barrett (http://www.justinanimator.com)\r\n" +
				"";
		
		propObj.AddParameter2( "credits", siString, creditString );

	} else {
		var propObj = dictionary.getObject("cgBreakdown");
	}
	
	
	var oLayout= propObj.ppgLayout;
	oLayout.clear();
	
	oLayout.AddTab( "Breakdown" ) ;
	
	oLayout.AddGroup( "" ) ;
		var sldr = oLayout.addItem("blendAmount", "Blend", siControlNumber);

		oLayout.AddRow() ;
			oLayout.AddButton("minusThreeQuartersBtn", "-3/4");
			oLayout.AddButton("minusHalfBtn", "-1/2");
			oLayout.AddButton("minusOneQuarterBtn", "-1/4");
			
		
			oLayout.AddButton("midBtn", "0");
			
		
			oLayout.AddButton("plusOneQuarterBtn", "+1/4");
			oLayout.AddButton("plusHalfBtn", "+1/2");
			oLayout.AddButton("plusThreeQuartersBtn", "+3/4");
		
		oLayout.EndRow() ;
	oLayout.EndGroup() ;
	
	oLayout.AddRow() ;
		oLayout.AddSpacer(5);
		oLayout.AddButton("breakdownBtn", "Breakdown Selected");
		oLayout.AddSpacer(5);
	oLayout.EndRow() ;
	
	oLayout.AddTab( "Overshoot" ) ;
		oLayout.AddGroup( "Overshoot" ) ;
			oLayout.AddRow() ;
				oLayout.AddButton("oShootMinusFullBtn", "-1");
				oLayout.AddButton("oShootMinusThreeQuartersBtn", "-3/4");
				oLayout.AddButton("oShootMinusHalfBtn", "-1/2");
				oLayout.AddButton("oShootMinusOneQuarterBtn", "-1/4");
			
				oLayout.AddButton("oShootPlusOneQuarterBtn", "+1/4");
				oLayout.AddButton("oShootPlusHalfBtn", "+1/2");
				oLayout.AddButton("oShootPlusThreeQuartersBtn", "+3/4");
				oLayout.AddButton("oShootPlusFullBtn", "1");
		
			oLayout.EndRow() ;
		oLayout.EndGroup() ;
	
		
	oLayout.AddTab( "Instructions" ) ;
		oLayout.AddString("Instructions", "",true, 200 );
		
	oLayout.AddTab( "Credits" ) ;
		oLayout.AddString("Credits", "",true, 200 );
		oLayout.addItem("debug", "Debug", siControlBoolean);


	
		
	oLayout.Logic =	breakdownBtn_OnClicked.toString() + 
					minusThreeQuartersBtn_OnClicked.toString() +
					minusHalfBtn_OnClicked.toString() +
					minusOneQuarterBtn_OnClicked.toString() +
					midBtn_OnClicked.toString() +
					plusOneQuarterBtn_OnClicked.toString() +
					plusHalfBtn_OnClicked.toString() +
					plusThreeQuartersBtn_OnClicked.toString() +
					oShootMinusFullBtn_OnClicked.toString() +
					oShootMinusThreeQuartersBtn_OnClicked.toString() +
					oShootMinusHalfBtn_OnClicked.toString() +
					oShootMinusOneQuarterBtn_OnClicked.toString() +
					oShootPlusOneQuarterBtn_OnClicked.toString() +
					oShootPlusHalfBtn_OnClicked.toString() +
					oShootPlusThreeQuartersBtn_OnClicked.toString() +
					oShootPlusFullBtn_OnClicked.toString() +
					blendAmount_OnChanged.toString() +					
					doBreakdown.toString();
	oLayout.Language = "JScript";
	 
	
	return(propObj);
}

//--------------------------------------------------//

function oShootMinusFullBtn_OnClicked() {
	var debug =  PPG.debug.value;
	application.cgBreakdown(-1, debug);
}

function oShootMinusThreeQuartersBtn_OnClicked() {
	var debug =  PPG.debug.value;
	application.cgBreakdown(-0.75, debug);
}

function oShootMinusHalfBtn_OnClicked() {
	var debug =  PPG.debug.value;
	application.cgBreakdown(-0.5, debug);
}

function oShootMinusOneQuarterBtn_OnClicked() {
	var debug =  PPG.debug.value;
	application.cgBreakdown(-0.25, debug);
}


function oShootPlusOneQuarterBtn_OnClicked() {
	var debug =  PPG.debug.value;
	application.cgBreakdown(1.25, debug);
}

function oShootPlusHalfBtn_OnClicked() {
	var debug =  PPG.debug.value;
	application.cgBreakdown(1.5, debug);
}

function oShootPlusThreeQuartersBtn_OnClicked() {
	var debug =  PPG.debug.value;
	application.cgBreakdown(1.75, debug);
}

function oShootPlusFullBtn_OnClicked() {
	var debug =  PPG.debug.value;
	application.cgBreakdown(2, debug);
}



//--------------------------------------------------//

function minusThreeQuartersBtn_OnClicked() {
	PPG.blendAmount.value = -0.75;	
	breakdownBtn_OnClicked();
}

function minusHalfBtn_OnClicked() {
	PPG.blendAmount.value = -0.5;	
	breakdownBtn_OnClicked();
}

function minusOneQuarterBtn_OnClicked() {
	PPG.blendAmount.value = -0.25;
	breakdownBtn_OnClicked();
}

function midBtn_OnClicked() {
	PPG.blendAmount.value = -0;
	breakdownBtn_OnClicked();
}

function plusOneQuarterBtn_OnClicked() {
	PPG.blendAmount.value = 0.25;
	breakdownBtn_OnClicked();
}

function plusHalfBtn_OnClicked() {
	PPG.blendAmount.value = 0.5;
	breakdownBtn_OnClicked();
}

function plusThreeQuartersBtn_OnClicked() {
	PPG.blendAmount.value = 0.75;
	breakdownBtn_OnClicked();
}

function blendAmount_OnChanged() {
	breakdownBtn_OnClicked();
}


function breakdownBtn_OnClicked() {
	var blendAmnt =  PPG.blendAmount.value;
	var debug =  PPG.debug.value;
	blendAmnt = (blendAmnt + 1) / 2;
	application.cgBreakdown(blendAmnt, debug);
}


//--------------------------------------------------//


function findObj( inObj ) {
	var oColl = new ActiveXObject("XSI.Collection"); 
	oColl.items = inObj;
	
	if (oColl.count > 0) {
		return(oColl(0));
	} else {
		return(false);
	}
	
}


function doBreakdown(inBlend) {
}



