-- 1) copy mesh so we make sure it has only an identity xform
-- 2) look at every vert, assembling a list of the 3 closest verts in opposite mesh
--- 2b choose from pivot point, bounding box, or world position matching
----2c expanding sphere method to find matches.
-- 3) Weight the lists of verts based on distance. Normalize.
-- 4) step through animation. Do complete bake copy of worldspace vert positions
--- filtered by weights. use SetVert to force worldspace






fn CopyMeshAnimations searchResolution minT MaxT minInfluences deformTension source target targetVerts = (

-- subFunction for getting a clean copy
fn ResetMesh resetObj = 
	(
	if resetObj != undefined do
			(
		disableSceneRedraw()
		-- Get the original node transform matrix
		local ntm = resetObj.transform
		
		-- The new object transform only inherits position
		resetObj.transform=transMatrix resetObj.pos
		
		-- Compute the pivot transform matrix
		local piv=resetObj.objecttransform * inverse resetObj.transform
		
		-- Reset the object offsets to 0
		resetObj.objectoffsetPos  = [0,0,0]
		resetObj.objectoffsetRot = (quat 0 0 0 1)
		resetObj.objectoffsetScale = [1,1,1]
		
		-- Take the position out of the original node transform matrix since we don't reset position
		ntm.translation=[0,0,0]
		
		-- Apply the pivot transform matrix to the modified original node transform matrix
		-- to get the XForm gizmo transform
		ntm = piv * ntm
		
		-- apply an XForm modifier to the node
		local xformMod=xform()
		addmodifier resetObj xformMod
		
		-- set the XForm modifier's gizmo tranform
		xformMod.gizmo.transform=ntm
		
	  	-- collapse object
		convertToMesh resetObj
		enableSceneRedraw()
		)
)

struct influence  (weight, vert)

--- setup
resetMesh target
select source
max tool animMode
set Animate off
sliderTime = animationRange.start

-- prepare VolumeSelect modifier for searching

	if classof source.modifiers[1] != Volumeselect then
		(
		ts = sphere radius:minT
		ts.wirecolor = green
		msm = Mesh_Select()
		msm.name = "bf_msm"
		AddModifier source msm
		vsm = VolumeSelect level:1 volume:3 node:TS
		vsm.name = "bf_vsm"
		AddModifier source (vsm)
		
		)
	else
		(
		ts = source.modifiers[1].node
		)
print ts
-- do the search in worldSpace

vertMask = #()

for vert in targetVerts do
	(
		ts.radius = minT
		replacePrompt ("matching vert: " + (vert as string))
		ts.pos = (getVert target vert)
		if source.SelectedVerts.count == 1  then
			(
			weightList = #( (influence weight:1 vert:source.selectedVerts[1].index) )
			)	
		else
			(
			while (source.selectedVerts.count < minInfluences ) and (ts.radius < MaxT )do
			  	(
				case of
					(
					(ts.radius < 1): ts.radius += .1 * searchResolution
					(ts.radius < 10): ts.radius += searchResolution
					(ts.radius < 100): ts.radius += 10 * searchResolution
					)
				)	
				
			weightList = #()
			
			for item in source.SelectedVerts do
				(
				skipFlag = false
	
				offset = (length (ts.pos - getvert source item.index))/ts.radius
			
				if offset < minT then
					(
					skipFlag = true
					append WeightList (influence weight:-1 vert:item.index)
					)
				else
					(
					if SkipFlag == true do exit
					rawWeight = 1 / (pow offset deformTension)
					append WeightList (influence weight:rawWeight vert:item.index)
					)
				)
				
			if source.SelectedVerts == #() do weightList = #()
	
			lookForIdentity = for item in weightList where item.weight == -1 collect item
						
			if lookForIdentity.count > 0 then
					(
					weightList = #( (influence weight:1 vert:LookForIdentity[1].vert) )
					)
				else	
					(
					rawTotal = 0.0
					for item in weightList do
							 (rawTotal = RawTotal + item.weight)
					
					for item in weightList do 
						(
						item.weight = (item.weight / rawTotal)
						)
					)
			)		
		append vertMask weightList 
	)

replacePrompt "Vertex mask completed"
delete ts
displayTempPrompt (heapsize as string) 1000
deleteModifier source source.Modifiers["bf_vsm"]
deleteModifier source source.Modifiers["bf_msm"]
checksum = 0
for item in VertMask do (checksum += item.count)
vertMatchRatio= (checkSum + .01) / VertMask.count
promptString = ("Vertex match ratio:" + (vertMatchRatio as string) )
replacePrompt promptString

if vertMatchRatio > 1 or (Querybox "This object as unassigned vertices. Continue?" == true) do
	(

	max tool animMode
	set Animate on
	
	for item in TargetVerts do 
		(
		animateVertex target item
		)
	
	coordsys world
	for T = animationRange.start to animationRange.end do
		(
		slidertime = t
		maskIndex = 0
		for item in targetVerts do
			(
			maskIndex += 1
			defPos = [0,0,0]
			for deformation in vertMask[maskIndex] do
				(
				defPos = defPos + (deformation.weight * (getVert source (deformation.vert)))
				)
			if VertMask[maskIndex].count > 0 do setVert target item defpos
			replacePrompt (item as string)
			)
			
		target.SelectedVerts = targetVerts
		update target
		move target.SelectedVerts [0,0,0]
		
		completeRedraw()
		sleep.1
		)
	max tool animMode
	set Animate off
	)
)

fn MeshAnimCopy = 
(
source = undefined

fn MeshAninCopy_legit testObj = classof testObj == Editable_mesh

rollout Settings "Mesh animation transfer settings"
(

group "animation source"
	(
	pickButton source "Choose source object" caption: "source object" width:128
	radiobuttons cloner  labels:#( "copy animations", "collapse source") columns:1

	)
group "target object"
	(
	pickButton target "Choose target object" caption: "target object" width:128 fn:MeshAninCopy_legit 
	radiobuttons getVerts  labels:#( "Use all vertices", "Use stack") columns:1
	)
group "vertex matching"
	(
	label l0 ""
	label l1 "Min. search radius" across:2 offset:[32 ,0] 
	spinner MinT type:#float range:[.0001,20,.5] fieldWidth:32 align:#left offset:[16 ,0]
	label l2 "Max. search radius" across:2 offset:[32 ,0] 
	spinner MaxT type:#integer range:[1,100,10] fieldWidth:32 align:#left offset:[16 ,0]
	label l21 "" 
	label l3 "search resolution:" offset:[-8,0]
	label l4 "finer" across:3 align:#right offset:[-8,0]
	slider searchResolution  align:#center range:[.01,1,.5] Width:96 offset:[-8,0]
	label L5 "coarse" align:#left offset:[-8,0]
	label l6  "Influences" across:2 offset:[32 ,0] 
	spinner minInfluences type:#integer range:[3,8,3] fieldWidth:32 align:#left offset:[16 ,0]
	)
	
group "deformation"
	(
	label d1  "falloff" across:2 offset:[32 ,0] 
	spinner deformTension type:#integer range:[1,5,0] fieldWidth:32 align:#left offset:[16 ,0]
	label d2 ""
	button doItSuckah "Copy Mesh animations"
	)

on source picked obj do
	(
	source.text = obj.name
	)

on target picked obj do
	(
	target.text = obj.name
	)
	
on doItSuckah pressed do
	(
	slidertime = (animationRange.start) 
	if source.object == undefined then
		(messagebox "No source object chosen")
	else
		(
		targetObj = (if cloner.state == 2 then (snapshot source.object) else (target.object))
		if targetObj != undefined do
			(
				if getVerts.state == 1 then
				(
				targetVerts = - #{(targetObj.numVerts + 1)}
				)
			else
				(
				try (targetVerts = for item in targetObj.selectedVerts collect item.index)
				catch ( targetVerts = - #{(targetObj.numVerts + 1)} )
				)

			CopyMeshAnimations \
				searchResolution.value \
				minT.value \
				MaxT.value \
				minInfluences.value \
				deformTension.value \
				source.object \
				targetObj \
				targetVerts 
			)	
		)
	)
)

dialog = newRolloutFloater "Mesh Animation Copy" 320 512
addRollout Settings dialog
)