struct vW  (index,\
	 weightArray = #(), \
	 includeArray = #{}, \
	 mirrorArray = #(), \
	fn make bpMod = 
		(
		newIncludeArray = #{}
		newWeightArray = #()
		for bNum = 1 to bpNbones bpMod do
			(
			included = (bpGetIncluded bpMod bNum index)

			if (included == true) then
				(
				weight = (bpGetFWeight bpMod bNum index)
				NewIncludeArray[bNum] = true
				newWeightArray[bNum] = weight
				)
			else
				(
				NewIncludeArray[bNum] = false
				newWeightArray[bNum] = 0
				)
			)
		includeArray = newIncludeArray 
		weightArray = newWeightArray 
		)
	)

--
fn getOppBone bpMod bNum = 
	(
	if classof obj == objectset do return undefined
	rootname = (bpGetBoneName bpMod bNum) as string
	findL = findstring rootname " L "
	findR = findstring rootname " R "
	case of
		(
		(findL == undefined and findR == undefined):
								( print ("root find failed " + rootname ); return bNum )
								-- (
								-- newname = rootname
								-- )
		(findL == undefined):	(
								newname = replace rootname findR 3 " L "
								)
		(findR == undefined): 	(
								newname = replace rootname findL 3 " R "
								)		
		)

	oppBone = (bpFindBone bpMod newname)
	if (oppBone == 0) do return bNum
	return oppBone
	)

--

fn VertexMirror obj mirrorAxis:#x tolerance:0.25 flip:false =
	(
	st = timestamp()
	-- simple prechecks
	bpMod =  obj.modifiers["Bones Pro 3"]
	if bpMod != undefined then 
			(
			
			-- which axis are we going to flip?
			mirrorAxis = mirrorAxis as name
		
			case mirrorAxis of 
				(
				#x:reverser = [1,0,0] 
				#y:reverser = [0,1,0]
				#z:reverser = [0,0,1] 
				default:reverser = [1,0,0]
				)
			if (flip == true) then reverser = reverser * -1
			
			
			-- collect array of 'vW' objecst on the "active" (usually negative) side
			masterVertList =  #()
			
			for item in obj.verts do
			 (
			 test = (item.pos * reverser)
			 newMasterVert = undefined
			 case of
			 	(
				(flip):(if (test.x + test.y + test.z > 0) do 
								(
								newMasterVert = vW item.index
								print NewMasterVert
								newMasterVert.make bpMod 
								)
							)
				(default):(if (test.x + test.y + test.z < 0) do 
								(
								newMasterVert = vW item.index
								newMasterVert.make bpMod 
								)
							)
				)
			if newMasterVert != undefined do append masterVertList newMasterVert
			)
				
			

			-- now we look at the verts and find their opposite numbers
			-- using a volume select mod and a sphere whose radius is the 
			-- tolerance value
			case mirrorAxis of 
				(
				#x:reverser = [-1,1,1] 
				#y:reverser = [1,-1,1]
				#z:reverser = [1,1,-1] 
				)
			max Modify mode
			TS = sphere radius:tolerance
			ts.wirecolor = blue
			selMod = VolumeSelect level:1 volume:3 node:TS
			modPanel.AddModToSelection selMod
			format "looking for opposite vertices\n"
			for item in masterVertList do
				(
				setWaitCursor()
				ts.pos = (obj.verts[item.index]).pos * reverser
				for eachVert in obj.selectedVerts do (append item.mirrorArray eachVert.index)
				if obj.selectedverts.count > 0 do (beep)
				setArrowCursor()
				)
				
			deleteModifier obj selMod
			-- build two arrays of max nodes which list (1) the bones in the order recognized by the
			-- bp modifiers and (2) a mirrored version of the same
			-- nb: this currently works ONLY in across the X (left-right) axis!!!
			
			flippedBoneArray = #()
			format "listing opposite bones:\n"
			for bNum = 1 to bpNbones bpMod do 
				(
				flippedBoneArray[bNum] = getOppBone bpMod bNum
				)
			
			-- we now go through the list of verts in MasterVertList and copy over
			-- the bonesPro values
			
			format "processing verts\n"
			disableSceneRedraw()
			prog = MasterVertList.count
			progCnt = 0.1
			progressStart "Processing Vertices"
			quitNow = false
			for item in MasterVertList do -- look at the master records
				(
				progCnt += 1
				for eachOppositeVertex in item.MirrorArray do -- iterate through the opposite vert list
					(
					bpVertSelect bpMod "none"
					bpSetVertSel bpMod eachOppositeVertex true
					
					if eachOppositeVertex != item.index do
						(
						for bNum = 1 to bpNbones bpMod do -- copy values bone by bone
							(
							targetBone = flippedBoneArray[bNum]
							if item.includeArray[bNum] == true then
								(
								bpSetIncluded bpMod targetBone 0 true	
								bpSetFWeight bpMod targetBone EachOppositeVertex item.weightArray[bNum]
								)
							else
								(
								bpSetIncluded bpMod targetBone 0 false
								bpSetFWeight bpMod targetBone EachOppositeVertex 0
								)
							)
						)
					)
				
				quitnow = getProgressCancel()
				progressUpdate ((progCnt / Prog) * 100)
				if quitnow == true do exit 
				)
		
		bpRefresh bpMod
		progressEnd()
		enableSceneRedraw()
		et = (timestamp() - st)/ 360.0
		print ("Elapsed time: " + et as string)
		delete ts
		)
	else
		( messagebox ("No Bones Pro modifier on object " + obj.name))
	
	)



fn showBpWeights obj =
	(
	-- simple prechecks
	print (classOf obj)
	if (classOf obj != Editable_mesh) do return 0;
	if (obj.selectedVerts.count < 1) do return 0;
	bpMod =  obj.modifiers["Bones Pro 3"]
	if bpMod != undefined then 
		(
-- 		for i in obj.selectedVerts do
		i = obj.selectedVerts[1]
			(
			msg = ("" as stringStream)
			for bNum = 1 to bpNbones bpMod do
				(
				included = (bpGetIncluded bpMod bNum i.index)
				
				if (included == true) do
					(
					weight = (bpGetFWeight bpMod bNum i.index)
					percent = (bpGetWeight bpMod bNum i.index) * 100
					
					format "% (%\%) %\n" (weight) percent (bpGetBoneName bpMod bNum) to:msg
					)
				)
			messagebox ( (msg as string) ) title: "Bone Weights"
			)
		)
	) 
					
