// 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 DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
// EVENT SHALL ALIAS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
//
//
// subDPaintableDeformer.mel
//
//
//	Description:
//
//		This is a wrapper method to all deformer commands that
//	would support a Proxy mode for the deforming subd.  The way this
//	works is, 
//		Scan the selection list and if there are subds, then
//	create a poly proxy for that, and deform both the subd and the
//	proxy with the already existing deformer commands.
//
//
//
//
//
//

source paintOnSubDUtils.mel;

proc myWarning(string $mesg)
{
	warning($mesg);
}

global proc subDPaintableDeformer(string $cmd, string $args) 
{
	global int $paintOnSubDUtils_comp = 0;
	string $deformerType = $cmd;

	string $inSubds[]=selectedSubDs();
	int $nSubds = size($inSubds);

	string $inNonSubds[]=selectedNonSubDs();
	int $nNonSubds = size($inNonSubds);

	if ($paintOnSubDUtils_comp && $nSubds != 1) {
		warning("More than one subdivision object cannot be deformed simultaneously");
		return;	
	}
	string $inJoints[]=`filterExpand -sm 3 -ex false`;	// Joints

	string $inSubdShape[];
	string $inObjects[]=`ls -sl`;
	if ($paintOnSubDUtils_comp) {
		$inObjects=`filterExpand -sm 36 -ex false`; // SubD Components
	} else {
		$inObjects=`filterExpand -sm 68 -ex false`; // SubD Object
	}

	int $i = 0, $shouldSplit = 1;
	int $depth = `subdiv -cl`;
	if ($depth == -2) $depth = 0;

	string $newNodes[], $convNodes[];
	string $polyProxys[], $polyProxyShape[], $tmpArr[];
	string $dType[], $oldHistory[];
	
	// If there are components selected, this loop should execute only once
	//
	for ($i = 0; $i < $nSubds; $i++) {
		$newNodes = createPolyProxy($inSubds[$i], $depth);
		$polyProxys[$i] = $newNodes[0]; // ProxyName...
		$convNodes[$i] = $newNodes[1];	// Conversion nodes

		$inSubdShape[$i] = getSubdShapeFromTransform($inSubds[$i]);
		$polyProxyShape[$i] = getMeshShapeFromTransform($polyProxys[$i]);

		clear($newNodes);
	}

	// The order in which we do things here is very important
	// for the Edit Membership Tool.  It's not too fussy for
	// regular clusters, but it is for skinClusters.
	//
	// Edit Membership uses the first valid member from 
	// "listConnections" to find an object's
	// related deformerSet.  The "listConnections" cmd
	// returns its members newest-to-oldest.
	// 
	// If the last (newest) skinCluster created is for a poly proxy,
	// this is the deformer set from which the Edit Membership tool
	// will select members.  They will appear selected in the title bar,
	// but because the proxy is an "intermediate" object, these
	// "selected" components will not be drawn in the modelling views.
	//
	// Therefore we first operate on proxies and *then* the subiv shapes. 
	// This will ensure that the "newest" deformerSets found by
	// the Edit Membership Tool belong to the subdiv shapes and not
	// the proxies.
	//
	// Note that this order holds true for components as well as
	// for whole shapes.
	//
	// Re-arrange the selection List such that
	// poly1, subd1, poly2, subd2 ... rest of the objects
	// 
	select -cl;
	if ($paintOnSubDUtils_comp) {
		// Select the polyVertices...
		//
		$inObjects=`filterExpand -sm 36 -ex true $inObjects`;
		string $convNode = $convNodes[0];
		int $nComp = size($inObjects);
		for ($i = 0; $i < $nComp; $i++) {
			tokenize $inObjects[$i] ".[]" $tmpArr;
            int $l = $tmpArr[2];
            int $r = $tmpArr[3];
			setAttr ($convNode+".is["+$i+"]") $l $r;
		}
		float $vtxId[] = `getAttr ($convNode+".ov")`;
		for ($i = 0; $i < $nComp; $i++) {
			select -add ($polyProxys[0]+".vtx["+$vtxId[$i]+"]");
		}

		// Now add the equivalent subdiv components.  They should be last
		// on the selection list.
		//
		select -add $inObjects;		// Not more than obj is allowed!
	} else {
		for ($i = 0; $i < $nSubds; $i++) {
			// Proxies first, then subds.
			//
			select -add $polyProxyShape[$i];
			select -add $inSubdShape[$i];
		}
	}

	select -add $inNonSubds;

	//	Before applying the deformation, we need to break certain
	//	connections, to effectively re-use the old deformer commands.
	//	There are 3 different situations to be handled:
	//		*) Without any history
	//		*) With possible proxy history (clusters)
	//		*) With regular history 
	//
	//	In any case, we need to break the old connections that
	//	are feeding into the selected subd shape.  Also, we need
	//  to break the connections that are feeding into the newly
	//	created proxy shape.
	//	These connections will be restored after calling the old
	//	deformer commands, to apply the deformation.
	//
	for ($i = 0; $i < $nSubds; $i++) {
		$dType[$i] = "null";
		$tmpArr = `listConnections -sh on ($inSubds[$i]+".create")`;
		if (size($tmpArr) > 0) {
			$dType[$i] = `nodeType $tmpArr[0]`;
		}

		if (   ($dType[$i] == "cluster") 
			|| ($dType[$i] == "skinCluster")
			|| ($dType[$i] == "jointCluster")) {	
			//
			//	Immediate past is a deformer with proxy.
			//
			$tmpArr = `listConnections -sh on -s on -p 1 ($convNodes[$i]+".inSubdiv")`;
			disconnectAttr $tmpArr ($convNodes[$i]+".inSubdiv");
			$tmpArr = `listConnections -sh on -s on -p 1 ($inSubds[$i]+".create")`;
			connectAttr $tmpArr ($convNodes[$i]+".inSubdiv");
		} else if ($dType[$i] == "null") {
			// There is no history, applying directly the
			// deformer will have problems with the downstream
			// nodes.  So just disconnect the downstream node connection
			// temporarily.
			disconnectAttr ($convNodes[$i]+".outMesh") ($polyProxyShape[$i]+".inMesh");			
			disconnectAttr ($inSubdShape[$i]+".outSubdiv") ($convNodes[$i]+".inSubdiv");			
		} else {			
			//
			//	There is some history.
			//
			$tmpArr = `listConnections -sh on -s on -p 1 ($inSubdShape[$i]+".create")`;
			$oldHistory[$i] = $tmpArr[0];
			disconnectAttr $oldHistory[$i] ($inSubdShape[$i]+".create");
			
			disconnectAttr ($convNodes[$i]+".outMesh") ($polyProxyShape[$i]+".inMesh");			
			disconnectAttr ($inSubdShape[$i]+".outSubdiv") ($convNodes[$i]+".inSubdiv");			
		}
	}
	// Commands should ignore this joint, if they are not needed....
	//
	select -add $inJoints;
	
	// Now create Cluster for this new selectionList!!
	//

	if ($cmd != "createSkinCluster") {
		$cmd += " " + $args;	
		eval($cmd); 
	} else {
		// skinCluster needs special processing!
		//
		$cmd += " \"" + $args + "\"";
		if (!$paintOnSubDUtils_comp) {
			for ($i = 0; $i < $nSubds; $i++) {
				// Be careful *not* to select the xfrom above the shapes,
				// since "createSkinCluster" finds targets via "ls -lf -dag"
				// and will again use the wrong order, creating skin 
				// clusters on the proxies *after* the subdiv.
				// 
				select -r $polyProxyShape[$i] $inSubdShape[$i] $inJoints;
				//print($cmd+"::"+$polyProxyShape[$i]+" "+$inSubdShape[$i]+" "+$inJoints[0]+"\n");
				eval($cmd); 
			}
			if (size($inNonSubds) > 0) {
				select -r $inNonSubds $inJoints;
				eval($cmd); 
			}
		} else {
			eval($cmd); 
		}
	}

	//	After applying the deformation, in order to restore the old
	//	connections, we need to know the name of the original shapes.
	//	Maya renames them to (oldName+"Orig#"), but its not safe to 
	//	use the above to guess the name.  So, we are going to look
	//	back at the history and get the names of the original shapes.
	//	That would be the 3rd earlier node in the history of the
	//	shape. (For the clusters)
	//	That would be the previous shape node in the history 
	//	(For the jointClusters)
	//
	string $originalProxyShape[];
	string $originalSubdShape[];

	for ($i = 0; $i < $nSubds; $i++) {
		if ($deformerType != "bindSkin") {
			// Regular clusters and skin clusters
			//
			$tmpArr = `listHistory -il 2 $polyProxyShape[$i]`;
			if (size($tmpArr) > 3) $originalProxyShape[$i] = $tmpArr[3];
			else myWarning("Internal error.");

			$tmpArr = `listHistory -il 2 $inSubdShape[$i]`;
			if (size($tmpArr) > 3) $originalSubdShape[$i] = $tmpArr[3];
			else myWarning("Internal error.");
		} else {
			// joint clusters 
			//
			$tmpArr = `listHistory -il 2 $polyProxyShape[$i]`;
			$tmpArr = dgFilterExpand($tmpArr, {"mesh"});
			if (size($tmpArr) > 1) $originalProxyShape[$i] = $tmpArr[1];
			else myWarning("Internal error.");

			$tmpArr = `listHistory -il 2 $inSubdShape[$i]`;
			$tmpArr = dgFilterExpand($tmpArr, {"subdiv"});
			if (size($tmpArr) > 1) $originalSubdShape[$i] = $tmpArr[1];
			else myWarning("Internal error.");
		}
	}

	for ($i = 0; $i < $nSubds; $i++) {
		if (   ($dType[$i] == "cluster") 
			|| ($dType[$i] == "skinCluster")
			|| ($dType[$i] == "jointCluster")) {	
			// do Nothing.....
			//
		} else if ($dType[$i] == "null") {
			// Reconnect the subdToPoly connection 
			// 
			connectAttr ($convNodes[$i]+".outMesh") ($originalProxyShape[$i]+".inMesh");
			connectAttr ($originalSubdShape[$i]+".outSubdiv") ($convNodes[$i]+".inSubdiv");
		} else {
			// Reconnect the old history connection 
			// 
			connectAttr $oldHistory[$i] ($originalSubdShape[$i]+".create");
			connectAttr ($convNodes[$i]+".outMesh") ($originalProxyShape[$i]+".inMesh");
			connectAttr ($originalSubdShape[$i]+".outSubdiv") ($convNodes[$i]+".inSubdiv");
		}

		int $exists = `attributeQuery -n $inSubdShape[$i] -ex pt_proxy`;
		addAttr -ln pt_proxy -sn ppx -at bool $polyProxyShape[$i];
		if (!$exists) {
			addAttr -ln pt_proxy -sn ppx -m -at bool $inSubdShape[$i];
			connectAttr ($inSubdShape[$i]+".pt_proxy[0]") ($polyProxyShape[$i]+".pt_proxy");
		} else {
			float $oldAttr[]=`getAttr  ($inSubdShape[$i]+".pt_proxy")`;
			int $ind = size($oldAttr);
			connectAttr ($inSubdShape[$i]+".pt_proxy["+$ind+"]") ($polyProxyShape[$i]+".pt_proxy");
		}		
		setAttr ($polyProxyShape[$i]+".visibility") 0;
		setAttr ($polyProxyShape[$i]+".intermediateObject") 1;
	}
}

