MaxScript writes bone conversion biped tool

1. The reason for making the conversion tool

  Hello everyone, I am Zhao. I often get some character models from various sources. After I get these models, I will find that they have skins, bones, and even motions.
  However, many of these resources are intercepted from the game. After being imported into 3DsMax, the bones of the character are bone type, not biped type. Anyone who is familiar with 3DsMax should know that the bone type needs to reconnect the IK by itself. If the bone is biped, it will be more convenient to use. So I have been looking for a tool that can convert bone bones to biped bones. I found some tools on the Internet, which can also be used, but I always feel that it is not particularly convenient. So I decided to make one myself.
  The full code for this tool is provided at the end. But I want to explain first that I developed this tool in the 3DsMax2018 version, and the support for Maxscript is different in different versions. Since I am free and open source, if you encounter API problems or bugs, please solve them yourself.
  By the way, if you have any tools you want to develop, you can also tell me. If it is simple, I can finish it for free and provide open source as an article. If it is complicated, I can also consider whether to charge for production according to my own time.

2. Tool instructions

1. What you need

insert image description here

  Here I take a game model of Onmyoji as an example. This is an fbx file of a character model with skin information, imported into 3DsMax.
insert image description here

  Take a look at the list of scene objects, and you will find that the bones of this model were originally made with biped, and then some custom bone bones were added.
  This kind of skeleton is made of biped, it is relatively easy to restore it to biped, because its structure and naming itself conform to the rules of biped.
  However, the bones of many character resource models are not made of biped, because there are many softwares for making 3D resources, not necessarily 3Dsmax, but maya, etc. So I also want to be compatible with other bone situations.

2. Tool introduction interface

insert image description here

  After running the script, you will see an interface consisting of 5 collapsible windows.
  The first one is the About window. Its content first displays the author's information, and then there are 4
  interfaces behind the simple steps of the operation, which correspond to the 4 major steps of the next operation. Next, I will explain one by one

1. Specify the bones of the biped architecture

insert image description here

  This tool window is the process of specifying the bones that are necessary for biped creation. You can see that there is a BoneList list above. The first column lists all the bone parts supported by the biped skeleton, and the second column uses asterisks to mark which parts are necessary. Because as the basic part of biped, without these bones, it cannot be generated.

This specified step can be divided into automatic and manual operations
(1) If the original bone is made by biped, then you can select the root node of the bone, and then click the SelectAndFit button, it will automatically traverse all the original bones, and according to The name of the bone, to match the part of the biped
(2) If the original bone name is not in accordance with the biped rules, you can also specify it manually. The specific operation is to select the root node of the bone and click the Select button. Next, first in the Select the bone object to be specified in the scene, and then click the corresponding bone part in the list. If you want to cancel the assignment of a certain bone, you can double-click the bone part in the list.
insert image description here

  For the second case of manual specification, because it is not easy to specify once, I also provide the function of saving and reading. After specifying, you can click the Save button. At this time, a window to save the file will open, allowing the user to select the file to be saved. The file uses the csv format. When you want to continue editing next time, first use the Select button to select the root node of the bone, and then click the Load button. At this time, a selection window for reading the file will open. Select the previously saved csv file, and you can upload the last result read came in.

2. Specify a custom bone

  Since the bones of the character are not necessarily all biped parts, there can also be many custom bone parts, such as the skirt of the clothes, the bones of the weapon, etc., so after specifying the biped bones, you can also specify custom bone parts skeleton. Of course, if not, you can also leave it unspecified.
insert image description here

  This operation must be done after the biped bone is specified or read in the first step, because it is also necessary to determine the type of the parent node of the custom bone.
The operation is also divided into two situations: automatic and manual
(1) If you want to use the custom function, after specifying the biped bone, select the root node of the original bone, and then click the Select And Check button. At this time, the tool will traverse under the root node All the nodes in , if they are not biped bones that have been specified before, are considered as custom bones.
(2) You can also manually specify some bones, and then click the Select And Add button to add them to the list. This function has deduplication, so if the bone has been added before, it will not be added repeatedly.
(3) Click the Clean button to clear all the specified custom bones, or double-click the bone name in the list to delete a single bone.
insert image description here

3. Create a new bone

After specifying the bones and custom bones of the biped part, you can generate a new biped bone
insert image description here

  In the Bone Controller panel, after entering the name of the biped to be generated, you can select One Key Create to create a biped and a custom bone with one click, and then automatically align their positions. If you don’t want to use one key, you can also manually generate step by step
  . Create Biped Only button to generate biped alone and Create Bones Only button to generate custom bone bones, and then use the ResizeBones button to manually align the bone position.
If it has been generated before, you can also specify the generated biped bone by selecting the new biped root node and clicking the SelectBiped button when continuing to operate.
insert image description here

This is the state of the model after the biped and custom bones have been generated. It can be seen that the newly generated bones are just aligned with the original model.

4. Skinning operation

After the skeleton is generated, the skinning operation can be performed.
insert image description here
  Since a model may be composed of multiple mesh parts, here you can single-select or multi-select the skinning meshes to be copied, and then click the Add button. Add it to the list. You can also select the grid that has been added, and then click the Remove button to remove it.
  Finally click the ReSkin button, the tool will copy the selected skin meshes, read their skin information, and transfer them to the newly generated bones.
insert image description here

This is the result after skinning. It can be seen that the newly generated mesh model can accurately follow the movement of the newly generated bones.

3. The principle of the tool

This version of the tool, I deliberately divided the steps according to the principle of thinking. From the tool, we can see that the whole process is divided into the following steps: 1. Raw bone data collection 2.
Generate
a new Biped
3. Align the bones
4. Obtain skinning information
5. Re-skinning
Now let's talk about the implementation of these steps in detail:

1. Raw skeleton data collection

Before collecting data, we must at least know what data needs to be collected.
Let’s take a look at the statement of creating a Biped in MaxScript:
biped.createNew <height_float> <angle_float> <wpos_point3> . . .
There are 3 data that are required:
1. Bone height
2. Rotation angle
3. World coordinates
followed by ellipsis, These are some optional parameters. In fact, they are all
bone parameters in Figure Mode in 3DsMax :
insert image description here

insert image description here

How do we know these parameters? We can only guess these parameters from the original bone bone. Therefore, the user must first specify the root bone of the original bone, and then read these bones through traversal.

1. Get a certain number of joints

From the specified Biped parts, the number of each bone part can be judged, such as Spine bones. If you judge how many Spine parts have specified bones, then the number of Spines can be obtained, and the same is true for other fingers and toes.
insert image description here

2.Triangle Pelvis和Triangle Neck

These two options will lead to changes in the tree structure of the bones.
If Triangle Pelvis is checked, L Thigh and R Thigh will be in the next layer of Spine
insert image description here

If Triangle Pelvis is unchecked, L Thigh and R Thigh will be on the same layer of Spine, and both are on the next layer of Pelvis
insert image description here

If Triangle Neck is checked, L Clavicle and R Clavicle will be on the same floor as Neck
insert image description here

If Triangle Neck is unchecked, L Clavicle and R Clavicle will be on the next layer of Neck
insert image description here

After knowing this relationship, when we collect bone information, we must pay special attention to the parent-child relationship of these bones to see which one they belong to.

3. How to get the height

In fact, there is no way to obtain the height, because the height here is literally the height from the top of the human skeleton to the sole of the foot. But our original bones have no thickness, so we can only calculate the coordinate position of the highest bone, not the top.
But the problem is not big, because the bone alignment will be used to modify the bone position below, so I got the distance from the Head to the Foot of the biped bone, as the height, which is equivalent to giving the bone a rough default value.

4. About rotation angle and coordinates

Because the bones will be aligned again below, the position and rotation are not important, just give a default value first.

5. Storage of bones

Since the tool has been divided into a list of biped parts and custom bones, I used two Struct structures to store the data structures of biped and custom bones.

2. Generate a new Biped

Through the above data collection, we have obtained the parameters necessary to create Biped.
Biped can be created by biped.createNew method.

local bipedHeight = maxHeight - minHeight
	newBipedObj = biped.createNew bipedHeight -90 [0,0,0] \
	arms:needArm \
	neckLinks:neckNum \ 
	spineLinks:spineNum \
	legLinks:legNum \
	tailLinks:tailNum \
	ponyTail1Links:ponyTail1Num \ 
	ponyTail2Links:ponyTail2Num \
	fingers:fingerNum \
	fingerLinks:fingerLinkNum \
	toes:toeNum \ 
	toeLinks:toeLinkNum \
	trianglePelvis:needTrianglePelvis \ 
	triangleNeck:needTriangleNeck \	
	prop1Exists:needProps1 \
	prop2Exists:needProps2 \
	prop3Exists:needProps3
	
	newBipedObj.controller.rootName = bipedName

There are 2 points worth noting:
1. If you want to change the name of the entire Biped together, such as changing from Bip001 to Bip002, it is not to traverse all the bones to change the name attribute object by object, but to get the controller of the Biped, and then modify the rootName, so that the whole The names of all biped nodes will change accordingly.
2. This step creates only the Biped part. In fact, many character models will add some bone-type bones as details on the basis of Biped, and these bone bones have not been generated in this step. Since the positions of these bones follow the normal biped bones, we will generate them after the biped bones are generated.

3. Align the bones

This step seems to be very simple, isn't it that each bone finds the bone with the same name as the original bone, and then copies the displacement, rotation and scaling information?
In fact, this is not the case, because:
1. In Biped, some bones can be moved directly, and some bones are moved by parent-child connection and IK. So if you directly set the position coordinates of the bones, many bones will not take effect. There are not many bones that can directly set the position coordinates, only the root bone, the neck, the left and right shoulders, the first Spine, the first joints of the fingers and toes.
2. The imported bone bone has a zoom of 1, but the biped bone zoom is not 1, which cannot be set according to the bone.
From this point of view, apart from the rotation information, there seems to be no information that can be directly set.
But the problem is not insoluble. Actually the above 2 questions are the same question. If we want to manually adapt the position of the bone, the normal way is to enter Figure Mode first, and then zoom in and out of the parent bone to an appropriate size to achieve the purpose of adjusting the position of the child bone. If you use scripts to operate, it is actually the same, you only need to calculate the scaling of the bones.
The calculation method is to calculate the distance between the coordinates of the parent bone and the coordinates of the child bone in the past, and this distance is the scaling value of the parent bone.
However, not all bones are calculated and scaled in this way. Here are several situations:
1. The root bone does not need to be scaled.
2. Pelvis of the pelvis, no matter what its parent-child structure is, its scaling is the distance from Pelvis to one of the thighs Thigh Multiply by 2
3. The last bone of the sternal spine does not need to be scaled, because its child bones can directly set the coordinates, and do not need to rely on the parent's scale to determine the position. The same is true for other children who can directly set the coordinates of the bones.
There is one more thing to pay attention to here. Biped objects cannot directly obtain information such as pos. They must first obtain transform, and then obtain pos, rotation, and scale.

4. Obtain skin information

For a skinned model, you need to get its skinned bone list first.
There is a point to note here. There are 2 lists of bones in the Skin, one is sorted according to the order of the UI display list, and the other is the actual bone Id during skin calculation. We should pay attention to the fact that what needs to be obtained is the actual bone Id, not the id that the UI shows sorted by.
So we need to get the number in the skin bone list through the skinOps.GetNumberBones method first, and then get the bone name of a certain bone id through the skinOps.GetBoneName method, and then save it.
The next step is to obtain information vertex by vertex.
There are 2 pieces of information that need to be obtained in a vertex skinning information:
1. How many bones are affected by a vertex
. 2. What is the weight of each bone that a vertex receives.
Here I also use the Struct structure to record the skin bone list and vertex skin weight information of a skinned mesh.

5. Re-skinning

Since we have the skinning information from the previous step, copy the original skinning mesh, add the Skin modifier, and then assign the skinning information to the new skinning mesh.

Fourth, the complete code:

(
--ui
local HelpWin
local BoneListWin
local CustomBoneListWin
local BoneCtrlWin
local SkinCtrlWin

--function
local GetMatch
local AddToBoneDict
local GetBoneInfoByName
local InitBoneList
local FitBoneToBiped
local GetFitName
local CreateBipedFun
local GetBipedHeight
local GetCommonBoneNum
local GetNeckNum
local GetSpineNum
local GetLegNum
local GetTailNum
local GetPonytail1Num
local GetPonytail2Num
local GetFingerNum
local GetFingerLinkNum
local GetToeNum
local GetProp
local CheckNeedArm
local CheckNeedTrianglePelvis
local CheckNeedTriangleNeck
local GetBipedName
local AddToCustomBoneDict
local GetCustomBoneInfoByName
local CheckCustomBone
local CheckOneCustomBone
local CleanCustomBone
local UpdateCustomBoneList
local CheckBoneIsBiped
local CheckNewBipedObj
local FitBoneToOrig
local CreateCustomBone
local ResizeNewBipedFun
local ResizeBoneFun
local RePositionBoneFun
local ResizeOneBone
local SaveBoneListFun
local LoadBoneListFun
local GetSaveBoneListPathFun
local GetLoadBoneListPathFun
local LoadBoneListFitOneBone
local GetSubBoneByName
local AddCustomBoneToList
local AddOneCustomBoneToList
local CheckSelectionIsBipedRoot
local CheckSelectSingleObj
local AddToSkinMeshList
local AddOneObjToSkinMeshList
local RemoveSkinMeshByName
local UpdateSkinMeshList
local SkinFun
local SkinOneMesh
local GetNewBoneByName
local InitNewBipedBoneList
local AddToNewBipedBoneList
local GetNewBipedBoneByName
--var
local mustHaveBoneList = #("root","Pelvis","Spine","L Thigh","L Calf","L Foot",\
	"L Toe0","R Thigh","R Calf","R Foot","R Toe0","Neck","L Clavicle","L UpperArm",\
	"L Forearm","L Hand","L Finger0","R Clavicle","R UpperArm","R Forearm","R Hand",\
	"R Finger0","Head")
local maxBoneList = #("root","Prop1","Prop2","Prop3","Pelvis","Spine","Spine1","Spine2",\
	"Spine3","Spine4","Spine5","Spine6","Spine7","Spine8","Spine9","Neck","Neck1","Neck2",\
	"Neck3","Neck4","Neck5","Neck6","Neck7","Neck8","Neck9","Neck10","Neck11","Neck12","Neck13",\
	"Neck14","Neck15","Neck16","Neck17","Neck18","Neck19","Neck20","Neck21","Neck22","Neck23",\
	"Neck24","Head","Ponytail1","Ponytail11","Ponytail12","Ponytail13","Ponytail14","Ponytail15",\
	"Ponytail16","Ponytail17","Ponytail18","Ponytail19","Ponytail110","Ponytail111","Ponytail112",\
	"Ponytail113","Ponytail114","Ponytail115","Ponytail116","Ponytail117","Ponytail118","Ponytail119",\
	"Ponytail120","Ponytail121","Ponytail122","Ponytail123","Ponytail124","Ponytail2","Ponytail21",\
	"Ponytail22","Ponytail23","Ponytail24","Ponytail25","Ponytail26","Ponytail27","Ponytail28",\
	"Ponytail29","Ponytail210","Ponytail211","Ponytail212","Ponytail213","Ponytail214","Ponytail215",\
	"Ponytail216","Ponytail217","Ponytail218","Ponytail219","Ponytail220","Ponytail221","Ponytail222",\
	"Ponytail223","Ponytail224","L Clavicle","L UpperArm","L Forearm","L Hand","L Finger0","L Finger01",\
	"L Finger02","L Finger03","L Finger1","L Finger11","L Finger12","L Finger13","L Finger2","L Finger21",\
	"L Finger22","L Finger23","L Finger3","L Finger31","L Finger32","L Finger33","L Finger4","L Finger41",\
	"L Finger42","L Finger43","R Clavicle","R UpperArm","R Forearm","R Hand","R Finger0","R Finger01",\
	"R Finger02","R Finger03","R Finger1","R Finger11","R Finger12","R Finger13","R Finger2","R Finger21",\
	"R Finger22","R Finger23","R Finger3","R Finger31","R Finger32","R Finger33","R Finger4","R Finger41",\
	"R Finger42","R Finger43","L Thigh","L Calf","L HorseLink","L Foot","L Toe0","L Toe01","L Toe02",\
	"L Toe1","L Toe11","L Toe12","L Toe2","L Toe21","L Toe22","L Toe3","L Toe31","L Toe32","L Toe4",\
	"L Toe41","L Toe42","R Thigh","R Calf","R HorseLink","R Foot","R Toe0","R Toe01","R Toe02","R Toe1",\
	"R Toe11","R Toe12","R Toe2","R Toe21","R Toe22","R Toe3","R Toe31","R Toe32","R Toe4","R Toe41",\
	"R Toe42","Tail","Tail1","Tail2","Tail3","Tail4","Tail5","Tail6","Tail7","Tail8","Tail9","Tail10",\
	"Tail11","Tail12","Tail13","Tail14","Tail15","Tail16","Tail17","Tail18","Tail19","Tail20","Tail21",\
	"Tail22","Tail23","Tail24")

local boneInfoDict
local selectedBoneRootObj
local bipedName
local newBipedObj
local customBoneInfoDict
local customBoneNameList
local skinMeshList
local skinInfoList
local newBipedObjNameList
local newBipedObjDict
--struct


	
struct VertexSkinInfo
(
	public
	index,
	boneIdList,
	weightList,
	fn AddWeightInfo id val = 
	(
		if this.weightList == undefined then
		(
			this.weightList = #()
		)
		if this.boneIdList == undefined then
		(
			this.boneIdList = #()
		)
		append this.boneIdList id
		append this.weightList val
	)
	
)

struct MeshSkinInfo
(
	skinObj,
	boneNameList,
	vertexInfoList,
	fn AddVertexInfo info = 
	(
		if vertexInfoList == undefined then
		(
			vertexInfoList = #()
		)
		append vertexInfoList info
	),	
	fn SetData skinMeshObj = 
	(
		if skinMeshObj == undefined then
			return 0
		this.skinObj = skinMeshObj
		select skinMeshObj
		local oldModSkin = skinMeshObj.modifiers[Skin]
		if oldModSkin == undefined then
		(
			print "No Skin on the object"
			return 0
		)
		max modify mode
		modPanel.setCurrentObject oldModSkin
		local boneNum = skinOps.GetNumberBones oldModSkin
		this.boneNameList = #()
		for i in 1 to boneNum do
		(
			local boneName = skinOps.GetBoneName oldModSkin i 1
			append this.boneNameList boneName
		)
		
		local vertexNum = GetNumVerts skinMeshObj.mesh
		this.vertexInfoList = #()
		for i in 1 to vertexNum do
		(
			local oneVertInfo = VertexSkinInfo()
			oneVertInfo.index = i
			local skinBoneNum = skinOps.GetVertexWeightCount oldModSkin i

			for j in 1 to skinBoneNum do
			(
				local tempBoneId = skinOps.GetVertexWeightBoneID  oldModSkin i j
				local tempWeight = skinOps.GetVertexWeight  oldModSkin i j
				oneVertInfo.AddWeightInfo tempBoneId tempWeight
			)
			append this.vertexInfoList oneVertInfo
		)
		
	)
	
)
	
struct CustomBoneInfoObj
(
	public 
	name,
	pos,
	rotation,
	scale,
	selectBone,
	newBone,
	parentName,
	parentIsBiped,
	fn SetData obj = 
	(
		this.selectBone = obj
		this.name = obj.name
		this.pos = obj.transform.pos
		this.rotation = obj.transform.rotation
		this.scale = obj.transform.scale
		if obj.parent != undefined then
		(
			local bipedBoneName = CheckBoneIsBiped obj.parent
			if bipedBoneName != undefined then
			(
				this.parentName = bipedBoneName
				this.parentIsBiped = true
			)
			else
			(
				this.parentName = obj.parent.name
				this.parentIsBiped = false
			)
		)
		else
		(
			this.parentName = undefined
			this.parentIsBiped = false
		)
	),
	fn SetNewBone val = 
	(
		this.newBone = val
	)
)
	
struct BoneInfoObj
(
	public
	name,
	isMust,
	selectBone,
	newBone,
	pos,
	rotation,
	scale,
	row,
	fn GetShowName = 
	(
		return this.name
	),
	fn GetMust = 
	(
		if this.isMust == true then
			return "*"
		else 
			return ""
	),
	fn SetName val = 
	(
		this.name = val
		local index = findItem mustHaveBoneList val
		if index >0 then
		(
			this.isMust = true
		)
		else
		(
			this.isMust = false
		)
	),
	fn SetSelectBone val = 
	(
		this.selectBone = val
		if this.selectBone != undefined then
		(
			this.pos = val.transform.pos
			this.rotation = val.transform.rotation
			this.scale = val.transform.scale
		)		
		else
		(
			this.pos = undefined
			this.rotation = undefined
			this.scale = undefined
		)
		this.UpdateRow()
	),
	fn SetNewBone val = 
	(
		this.newBone = val
	),
	fn SetRow val = 
	(
		this.row = val
	),
	fn UpdateRow = 
	(
		if this.row != undefined then
		(
			local content = "";
			if this.selectBone != undefined then
			(
				content = this.selectBone.name
			)
			this.row.subItems.item[2].text = content
		)
	)
)
	
--tool function
fn GetMatch str1 str2 = 
(
	local regexStr = "*"+str2+"*"
	return matchPattern str1 pattern:regexStr
)

fn GetMatchEnd str1 str2 = 
(
	local regexStr = "*"+str2
	return matchPattern str1 pattern:regexStr
)

fn AddToBoneDict info = 
(
	if boneInfoDict == undefined then
	(
		boneInfoDict = #()
	)
	local index = findItem maxBoneList info.name
	if index> 0 then
	(
		boneInfoDict[index] = info
	)
	
)

fn GetBoneInfoByName val = 
(
	if boneInfoDict == undefined then
	(
		return undefined
	)
	local index = findItem maxBoneList val
	if index > 0 then
		return boneInfoDict[index]
	else
		return undefined
)

fn AddToCustomBoneDict info = 
(
	if customBoneInfoDict == undefined then
	(
		customBoneInfoDict = #()
	)
	if customBoneNameList == undefined then
	(
		customBoneNameList = #()
	)
	local index = findItem customBoneNameList info.name
	if index >0 then
	(
		customBoneInfoDict[index] = info
	)
	else
	(
		append customBoneNameList info.name
		append customBoneInfoDict info
	)
)

fn GetCustomBoneInfoByName val = 
(
	if customBoneNameList == undefined or customBoneInfoDict == undefined then
	(
		return undefined
	)
	local index = findItem customBoneNameList val
	if index > 0 then
	(
		return customBoneInfoDict[index]
	)
	else
	(
		return undefined
	)
	
)

fn RemoveCustomBoneInfoByName val = 
(
	if customBoneNameList == undefined or customBoneInfoDict == undefined then
	(
		return 0
	)
	local index = findItem customBoneNameList val
	if index < 0 then
	(
		return 0
	)
	deleteItem customBoneNameList index
	deleteItem customBoneInfoDict index
	UpdateCustomBoneList()
)

fn CheckBoneIsBiped obj = 
(
	
	local curName = undefined
	for i in 1 to boneInfoDict.count do
	(
		local info = boneInfoDict[i]
		if info.selectBone != undefined and info.selectBone == obj then
		(
			curName = info.name
			break
		)
	)
	return curName
)

--ui function
fn InitBoneList = 
(	
	boneInfoDict = #()
	for i in 1 to maxBoneList.count do
	(
		local info = BoneInfoObj()
		info.SetName maxBoneList[i]
		AddToBoneDict info
	)
)

fn ShowMsg msg = 
(
	MessageBox msg title:"Tips"
)

fn GetFitBoneInfo val = 
(
	
	local index = 0
	local newName = val
	if newName != "root" then
		newName = replace val 1 (bipedName.count+1) ""
	for i in 1 to maxBoneList.count do
	(
		if newName == maxBoneList[i] then
		(
			index = i
			break
		)
	)
	if index >0 then
	(
		return boneInfoDict[index]
	)
	else
	(
		return undefined
	)
	
)

fn FitBoneToBiped obj =
(
	local objName = obj.name
	if objName == bipedName then
	(
		objName = "root"
	)
	local info = GetFitBoneInfo objName
	if info != undefined then
		info.SetSelectBone obj
	
	local childrenList = obj.children
	if childrenList != undefined and childrenList.count >0 then
	(
		for i in 1 to childrenList.count do
		(
			FitBoneToBiped childrenList[i]
		)
	)
)


fn FitBoneToOrig obj =
(
	local objName = obj.name
	if objName == bipedName then
	(
		objName = "root"
	)
	local boneType = classof obj
	if boneType!= Dummy and (GetMatch objName "Footstep") == false then
	(
		if boneType == Biped_Object then
		(
			local info = GetFitBoneInfo objName
			if info != undefined then
				info.SetNewBone obj
		)
		else
		(
			local info = GetCustomBoneInfoByName objName
			if info != undefined then
				info.SetNewBone obj
		)
	)
	local childrenList = obj.children
	if childrenList != undefined and childrenList.count >0 then
	(
		for i in 1 to childrenList.count do
		(
			FitBoneToOrig childrenList[i]
		)
	)
)


fn CheckMustBone = 
(
	for item in boneInfoDict do
	(
		if item.isMust == true and item.selectBone == undefined then
		(
			return item.name
		)
	)
	return undefined
)


fn GetBipedHeight = 
(
	local headInfo = GetBoneInfoByName("Head")
	local footInfo = GetBoneInfoByName("L Foot")
	return (distance headInfo.pos footInfo.pos)
)

fn GetCommonBoneNum name1 name2 = 
(
	local indexStart = findItem maxBoneList name1
	local indexEnd = findItem maxBoneList name2
	local num = 0;
	for i in indexStart to indexEnd do
	(
		local curName = maxBoneList[i]
		local info = GetBoneInfoByName(curName)
		if info != undefined and info.selectBone != undefined then
		(
			num = num +1
		)
	)
	return num
)


fn GetNeckNum = 
(
	return GetCommonBoneNum "Neck" "Neck24"
)

fn GetSpineNum = 
(
	return GetCommonBoneNum "Spine" "Spine9"
)

fn GetLegNum = 
(
	local num = 3
	local info = GetBoneInfoByName "L HorseLink"
	if info != undefined and info.selectBone!=undefined then
	(
		num = 4
	)
	return num
)

fn GetTailNum = 
(
	return GetCommonBoneNum "Tail" "Tail24"
)

fn GetPonytail1Num = 
(
	return GetCommonBoneNum "Ponytail1" "Ponytail124"
)

fn GetPonytail2Num = 
(
	return GetCommonBoneNum "Ponytail2" "Ponytail224"
)

fn GetFingerNum = 
(
	local info = GetBoneInfoByName "L Finger4"
	if info != undefined and info.selectBone != undefined then
	(
		return 5
	)
	
	info = GetBoneInfoByName "L Finger3"
	if info != undefined and info.selectBone != undefined then
	(
		return 4
	)
	
	info = GetBoneInfoByName "L Finger2"
	if info != undefined and info.selectBone != undefined then
	(
		return 3
	)
	
	info = GetBoneInfoByName "L Finger1"
	if info != undefined and info.selectBone != undefined then
	(
		return 2
	)
	
	info = GetBoneInfoByName "L Finger0"
	if info != undefined and info.selectBone != undefined then
	(
		return 1
	)
	
	return 0
)

fn GetFingerLinkNum = 
(
	return GetCommonBoneNum "L Finger0" "L Finger03"
)

fn GetToeNum = 
(
	local info = GetBoneInfoByName "L Toe4"
	if info != undefined and info.selectBone != undefined then
	(
		return 5
	)
	
	info = GetBoneInfoByName "L Toe3"
	if info != undefined and info.selectBone != undefined then
	(
		return 4
	)
	
	info = GetBoneInfoByName "L Toe2"
	if info != undefined and info.selectBone != undefined then
	(
		return 3
	)
	
	info = GetBoneInfoByName "L Toe1"
	if info != undefined and info.selectBone != undefined then
	(
		return 2
	)
	
	info = GetBoneInfoByName "L Toe0"
	if info != undefined and info.selectBone != undefined then
	(
		return 1
	)
	
	return 0
)

fn GetToeLinkNum = 
(
	return GetCommonBoneNum "L Toe0" "L Toe02"
)

fn GetProp val = 
(
	if val == 1 then
	(
		info = GetBoneInfoByName "Prop1"
		if info != undefined and info.selectBone != undefined then
		(
			return true
		)
		else
		(
			return false
		)
	)
	else if val == 2 then
	(
		info = GetBoneInfoByName "Prop2"
		if info != undefined and info.selectBone != undefined then
		(
			return true
		)
		else
		(
			return false
		)
	)
	else if val == 3 then
	(
		info = GetBoneInfoByName "Prop3"
		if info != undefined and info.selectBone != undefined then
		(
			return true
		)
		else
		(
			return false
		)
	)
	else
	(
		return false
	)

)

fn CheckNeedArm = 
(
	info = GetBoneInfoByName "L UpperArm"
	if info != undefined and info.selectBone != undefined then
	(
		return true
	)
	else
	(
		return false
	)
)

fn CheckNeedTrianglePelvis =
(
	local result = false;
	local thighInfo = GetBoneInfoByName "L Thigh"
	local spineInfo = GetBoneInfoByName "Spine"
	if thighInfo!= undefined and thighInfo.selectBone != undefined then
	(
		if spineInfo!= undefined and spineInfo.selectBone != undefined then
		(
			if thighInfo.selectBone.parent == spineInfo.selectBone then
			(
				result = true
			)
		)
	)
	return result
)

fn CheckNeedTriangleNeck = 
(
	local result = true;
	local clavicleInfo = GetBoneInfoByName "L Clavicle"
	local neckInfo = GetBoneInfoByName "Neck"
	if clavicleInfo!= undefined and clavicleInfo.selectBone != undefined then
	(
		if neckInfo!= undefined and neckInfo.selectBone != undefined then
		(
			if clavicleInfo.selectBone.parent == neckInfo.selectBone then
			(
				result = false
			)
		)
	)
	return result
)

fn CreateBipedFun = 
(
	local missingName = CheckMustBone()
	if missingName != undefined then
	(
		ShowMsg("MustNeed Bone Missing:"+missingName)
		return 0
	)
	local bipedHeight = GetBipedHeight()
	local numNum = GetNeckNum()
	local neckNum = GetNeckNum()
	local spineNum = GetSpineNum()
	local legNum = GetLegNum()
	local tailNum = GetTailNum()
	local ponytail1Num = GetPonytail1Num()
	local ponytail2Num = GetPonytail2Num()
	local fingerNum = GetFingerNum()
	local fingerLinkNum = GetFingerLinkNum()
	local toeNum = GetToeNum()
	local toeLinkNum = GetToeLinkNum()
	local needProp1 = GetProp 1
	local needProp2 = GetProp 2
	local needProp3 = GetProp 3
	local needArm = CheckNeedArm()
	local needTrianglePelvis = CheckNeedTrianglePelvis()
	local needTriangleNeck = CheckNeedTriangleNeck()
	
	newBipedObj = biped.createNew bipedHeight -90 [0,0,0] \
	arms:needArm \
	neckLinks:neckNum \ 
	spineLinks:spineNum \
	legLinks:legNum \
	tailLinks:tailNum \
	ponyTail1Links:ponytail1Num \ 
	ponyTail2Links:ponytail2Num \
	fingers:fingerNum \
	fingerLinks:fingerLinkNum \
	toes:toeNum \ 
	toeLinks:toeLinkNum \
	trianglePelvis:needTrianglePelvis \ 
	triangleNeck:needTriangleNeck \	
	prop1Exists:needProp1 \
	prop2Exists:needProp2 \
	prop3Exists:needProp3
	
	newBipedObj.controller.rootName = GetBipedName()	
	FitBoneToOrig newBipedObj
)

fn SetBipedName val = 
(
	bipedName = val
	BoneCtrlWin.bipedNameTxt.text = val
)

fn GetBipedName = 
(
	return BoneCtrlWin.bipedNameTxt.text
)

fn CheckCustomBone = 
(
	if selectedBoneRootObj == undefined then
	(
		ShowMsg("Please select boneRootFirst!")
		return 0
	)
	customBoneInfoDict = #()
	customBoneNameList = #()
	CheckOneCustomBone selectedBoneRootObj
	UpdateCustomBoneList()
)

fn CheckOneCustomBone obj =
(
	if (classof obj)!= Dummy and (GetMatch obj.name "Footstep") == false and (GetMatchEnd obj.name "Nub") == false then
	(
		local bipedBoneName = CheckBoneIsBiped obj
		if bipedBoneName == undefined then
		(
			local info = CustomBoneInfoObj()
			info.SetData obj
			AddToCustomBoneDict info
		)
	)
	local childrenList = obj.children
	if childrenList != undefined and childrenList.count >0 then
	(
		for i in 1 to childrenList.count do
		(
			CheckOneCustomBone childrenList[i]
		)
	)
)	

fn CleanCustomBone = 
(
	customBoneInfoDict = #()
	customBoneNameList = #()
	UpdateCustomBoneList()
)

fn UpdateCustomBoneList = 
(
		CustomBoneListWin.boneDataList.Clear()
		CustomBoneListWin.boneDataList.Fullrowselect = true
		CustomBoneListWin.boneDataList.GridLines = true
	    CustomBoneListWin.boneDataList.View = CustomBoneListWin.boneDataList.View.Details
	    
		if customBoneInfoDict == undefined or customBoneInfoDict.count <=0 then
		(
			return 0
		)
	    CustomBoneListWin.boneDataList.Columns.Add "BoneName" 100
		CustomBoneListWin.boneDataList.Columns.Add "parentType" 100
	    CustomBoneListWin.boneDataList.Columns.Add "parentName" 200
	    

		for i = 1 to customBoneInfoDict.count do
		(
			local info = customBoneInfoDict[i]
			row = dotNetObject "System.Windows.Forms.ListViewItem"
	        row.Text = info.name
			local parentType = ""
			local parentName = ""
			if info.parentName != undefined then
			(
				parentName = info.parentName
				if info.parentIsBiped == true then
				(
					parentType = "biped"
				)
				else
				(
					parentType = "bone"
				)
			)
	        row.SubItems.Add(parentType)
			row.SubItems.Add(parentName)
	        CustomBoneListWin.boneDataList.Items.Add(row)
		)
)

fn CheckNewBipedObj = 
(
	if newBipedObj == undefined then
	(
		ShowMsg "Please create biped or select biped first"
		return 0
	)
	FitBoneToOrig newBipedObj
)

fn CreateCustomBone = 
(
	if customBoneInfoDict == undefined and customBoneInfoDict.count == 0 then
	(
		return 0
	)
	for i in 1 to customBoneInfoDict.count do
	(
		local info = customBoneInfoDict[i]
		if info.selectBone != undefined then
		(
			local newBone = copy info.selectBone
			newBone.name = info.selectBone.name
			info.SetNewBone newBone
			if info.parentName != undefined then
			(
				if info.parentIsBiped == true then
				(
					local parentInfo = GetBoneInfoByName info.parentName
					if parentInfo != undefined and parentInfo.newBone != undefined then
					(
						newBone.parent = parentInfo.newBone
					)
				)
				else
				(
					local parentInfo = GetCustomBoneInfoByName info.parentName
					if parentInfo != undefined and parentInfo.newBone != undefined then
					(
						newBone.parent = parentInfo.newBone
					)
				)
			)
		)
	)
)

fn ResizeNewBipedFun = 
(
	if newBipedObj == undefined then
	(
		ShowMsg "Please create biped or select biped first"
		return 0
	)
	newBipedObj.controller.figureMode = true
	ResizeBoneFun newBipedObj
	RePositionBoneFun()
	newBipedObj.controller.figureMode = false
)

fn ResizeBoneFun obj = 
(
	local objName = obj.name
	if objName == bipedName then
	(
		objName = "root"
	)
	local boneType = classof obj
	if boneType!= Dummy and (GetMatch objName "Footstep") == false then
	(
		if boneType == Biped_Object then
		(
			local info = GetFitBoneInfo objName
			ResizeOneBone info
		)

	)
	local childrenList = obj.children
	if childrenList != undefined and childrenList.count >0 then
	(
		for i in 1 to childrenList.count do
		(
			ResizeBoneFun childrenList[i]
		)
	)
)

fn ResizeOneBone info = 
(
	if info.selectBone == undefined or info.newBone == undefined then
		return 0
	local childrenList =info.selectBone.children
	if childrenList == undefined or childrenList.count ==0 then
	(
		return 0
	)
	if info.name == "root" then
		return 0
	if info.name == "L Foot" or info.name == "R Foot" then
		return 0
	if info.name == "Pelvis" then
	(
		local nextInfo = GetBoneInfoByName "L Thigh"
		if nextInfo != undefined then
		(
			local tempScale = distance info.pos nextInfo.pos
			tempScale = tempScale*2
			biped.setTransform info.newBone #scale [tempScale,tempScale,tempScale] true
		)
	)
	else
	(
		if (GetMatch info.name "Spine") == true then
		(
			if (GetMatch childrenList[1].name "Spine") == false then
			(
				return 0
			)
		)
		local maxVal = 0
		for i in 1 to childrenList.count do
		(
			local tempVal = distance info.pos childrenList[i].transform.pos
			if tempVal >maxVal then
				maxVal = tempVal
		)
		if maxVal > 0 then
		(
			biped.setTransform info.newBone #scale [maxVal,maxVal,maxVal] true
		)
	)
	
)

fn RePositionBoneFun = 
(
	if boneInfoDict != undefined and boneInfoDict.count >0 then
	(
		for i in 1 to boneInfoDict.count do
		(
			local info = boneInfoDict[i]
			if info.selectBone != undefined and info.newBone != undefined then
			(
				biped.setTransform info.newBone #pos info.pos true
				biped.setTransform info.newBone #rotation info.rotation true
				biped.setTransform info.newBone #pos info.pos true
				biped.setTransform info.newBone #rotation info.rotation true
			)
		)
	)
	
	if customBoneInfoDict != undefined and customBoneInfoDict.count >0 then
	(
		for i in 1 to customBoneInfoDict.count do
		(
			local info = customBoneInfoDict[i]
			if info.selectBone != undefined and info.newBone != undefined then
			(
				info.newBone.pos = info.selectBone.pos
				info.newBone.rotation = info.selectBone.rotation
				info.newBone.scale = info.selectBone.scale
			)
		)
	)
)

fn GetSaveBoneListPathFun = 
(
	local savePath = getSaveFileName types:"csv(*.csv)|*csv"
	if savePath == undefined then
	(
		return undefined
	)
	if (matchPattern savePath pattern:"*.csv") == false then
	(
		savePath+=".csv"
	)
	return savePath
)

fn SaveBoneListFun = 
(
	if boneInfoDict == undefined or boneInfoDict.count == 0 then
	(
		ShowMsg("No data can save!")
		return 0
	)
	local savePath = GetSaveBoneListPathFun()
	if savePath == undefined then
	(
		return 0
	)
	local content = "";
	for i in 1 to boneInfoDict.count do
	(
		local info = boneInfoDict[i]
		if info.selectBone != undefined then
		(
			content+=info.name+","+info.selectBone.name
			content += "\n"
		)
	)
	if content == "" then
	(
		ShowMsg("No bone can save,Please assign or autofit bone first!")
		return 0
	)
	local f = createFile savePath
	format content to:f
	close f
	ShowMsg ("save file to :"+savePath)
	
)

fn GetLoadBoneListPathFun = 
(
	local loadPath = getOpenFileName types:"csv(*.csv)|*csv"
	if loadPath == undefined then
	(
		return undefined
	)

	return loadPath
)

fn LoadBoneListFun = 
(
	if selectedBoneRootObj == undefined then
	(
		ShowMsg "Please select boneRoot"
		return 0
	)

	local loadPath = GetLoadBoneListPathFun()
	if loadPath == undefined then
	(
		return 0
	)
	local f = openFile loadPath
	local lineList = #()
	while not eof f do
	(
		local lineStr = readLine f
		append lineList lineStr
	)
	close f
	for i in 1 to lineList.count do
	(
		LoadBoneListFitOneBone lineList[i]
	)
)

fn LoadBoneListFitOneBone val = 
(
	if selectedBoneRootObj == undefined then
		return 0
	local strArr = filterString val ","
	if strArr == undefined or strArr.count < 2 then
	(
		return 0
	)
	local key = strArr[1]
	local boneName = strArr[2]
	local info = GetBoneInfoByName key
	if info == undefined then
	(
		return 0
	)
	local targetBoneObj = GetSubBoneByName selectedBoneRootObj boneName
	if targetBoneObj != undefined then
	(
		info.SetSelectBone targetBoneObj
	)
)

fn GetSubBoneByName obj val = 
(
	if obj.name == val then
		return obj
	
	local resultObj = undefined
	local childrenList = obj.children
	if childrenList != undefined and childrenList.count > 0 then
	(
		for i in 1 to childrenList.count do
		(
			local subResult = GetSubBoneByName childrenList[i] val
			if subResult != undefined then
			(
				resultObj = subResult
				break
			)
		)
	)
	return resultObj
)

fn AddCustomBoneToList = 
(
	if $ == undefined then
		return 0
	local tempList = #()
	local tempType = classof $
	if tempType == ObjectSet then
	(
		if $.count > 0 then
		(
			for i in 1 to $.count do
			(
				append tempList $[i]
			)
		)
	)
	else
	(
		append tempList $
	)
	if tempList.count == 0 then
		return 0
	
	for i in 1 to tempList.count do
	(
		AddOneCustomBoneToList tempList[i]
	)
	UpdateCustomBoneList()
	
)

fn AddOneCustomBoneToList obj = 
(
	local objType = classOf obj
	if objType == Dummy or objType == Biped_Object then
		return 0
	if customBoneNameList != undefined then
	(
		local index = findItem customBoneNameList obj.name
		if index >0 then
			return 0
	)
	
	local info = CustomBoneInfoObj()
	info.SetData obj
	AddToCustomBoneDict(info)
	
)

fn CheckSelectionIsBipedRoot obj = 
(
	if obj == undefined then
		return false
	
	local objType = classof obj
	if objType != Biped_Object then
		return false
	
	objType = classof obj.controller
	if objType != Vertical_Horizontal_Turn then
		return false
	
	return true
)

fn CheckSelectSingleObj obj = 
(
	if obj == undefined then
		return false
	
	local objType = classof obj
	if objType == ObjectSet or objType == Dummy then 
		return false
	
	return true
)

fn AddToSkinMeshList obj = 
(
	if obj == undefined then
		return 0
	
	if skinMeshList == undefined then
		skinMeshList = #()
	
	local objType = classof obj
	local addList = #()
	if objType == ObjectSet then
	(
		for i in 1 to obj.count do
		(
			append addList obj[i]
		)
	)
	else
	(
		append addList obj
	)
	local realAddList = #()
	for i in 1 to addList.count do
	(
		local subObj = addList[i]
		if subObj.modifiers[Skin] != undefined then
		(
			append realAddList subObj
		)
	)
	if realAddList.count == 0 then
	(
		ShowMsg "No Skin on selected objs!"
		return 0
	)
	
	for i in 1 to realAddList.count do
	(
		AddOneObjToSkinMeshList realAddList[i]
	)
	
	UpdateSkinMeshList()
)

fn AddOneObjToSkinMeshList obj = 
(
	local isExist = false
	if skinMeshList.count > 0 then
	(
		for i in 1 to skinMeshList.count do
		(
			if skinMeshList[i] == obj then
			(
				isExist = true
				break
			)
		)
	)
	if isExist == true then
		return 0
	append skinMeshList obj
)

fn RemoveSkinMeshByName val = 
(
	if skinMeshList == undefined or skinMeshList.count == 0 then
		return 0
	
	local index = 0
	for i in 1 to skinMeshList.count do
	(
		if skinMeshList[i].name == val then
		(
			index = i
			break
		)
	)
	if index == 0 then
		return 0
	
	deleteItem skinMeshList index
	UpdateSkinMeshList()
)

fn UpdateSkinMeshList = 
(
	SkinCtrlWin.skinDataList.Items.clear()
	if skinMeshList == undefined or skinMeshList.count ==0 then
		return 0
	
	for i in 1 to skinMeshList.count do
	(
		SkinCtrlWin.skinDataList.Items.Add(skinMeshList[i].name)
	)
)


fn InitNewBipedBoneList = 
(
	newBipedObjNameList = #()
	newBipedObjDict = #()
	if boneInfoDict == undefined or boneInfoDict.count == 0 then
		return 0
	
	for i in 1 to boneInfoDict.count do
	(
		local info = boneInfoDict[i]
		if info.newBone != undefined then
			AddToNewBipedBoneList info.selectBone.name info.newBone
	)
)

fn AddToNewBipedBoneList val obj = 
(
	if newBipedObjNameList == undefined then
		newBipedObjNameList = #()
	
	if newBipedObjDict == undefined then
		newBipedObjDict = #()
	
	append newBipedObjNameList val
	append newBipedObjDict obj
)

fn GetNewBipedBoneByName val = 
(
	if newBipedObjNameList == undefined or newBipedObjDict == undefined then
		return undefined 
	
	local index = findItem newBipedObjNameList val
	if index == 0 then
		return undefined
	
	return newBipedObjDict[index]
)

fn SkinFun = 
(
	if skinMeshList == undefined or skinMeshList.count == 0 then
	(
		ShowMsg "Please add skinMesh first!"
		return 0
	)
	InitNewBipedBoneList()
	skinInfoList = #()
	for i in 1 to skinMeshList.count do
	(
		local info = MeshSkinInfo()
		info.SetData skinMeshList[i]
		append skinInfoList info
	)
	for i in 1 to skinInfoList.count do
	(
		SkinOneMesh skinInfoList[i]
	)

)

fn SkinOneMesh info = 
(
	local newSkinMeshObj = copy info.skinObj
	deleteModifier newSkinMeshObj 1
	select newSkinMeshObj
	ModPanel.addModToSelection(Skin()) ui:on
	local modSkin = newSkinMeshObj.modifiers[Skin]
	for i in  1 to info.boneNameList.count do
	(
		local boneNode = GetNewBoneByName info.boneNameList[i]
		if boneNode != undefined then
		(
			skinOps.addbone modSkin boneNode -1
		)
	)
	vertexNum = GetNumVerts newSkinMeshObj.mesh
	for i in 1 to vertexNum do
	(
		--print i
		skinOps.SetVertexWeights modSkin i info.vertexInfoList[i].boneIdList info.vertexInfoList[i].weightList
	)
)

fn GetNewBoneByName val = 
(
	local info = GetCustomBoneInfoByName val 
	if info != undefined then
		return info.newBone
	

	local bipedBoneObj = GetNewBipedBoneByName val
	if bipedBoneObj != undefined then
		return bipedBoneObj
	
	return undefined
)
	

--ui


--HelpWin
rollout HelpWin "About" width:400 height:212
(
	label 'lbl1' "BoneToBipedTool" pos:[23,10] width:89 height:21 align:#left
	label 'lbl37' "author:Li Weizhao" pos:[23,32] width:157 height:21 align:#left
	HyperLink 'theHyperlink' "https://blog.csdn.net/liweizhao" pos:[54,57] width:309 height:21 address:"https://blog.csdn.net/liweizhao" align:#left
	--label 'lbl38' "blog:https://blog.csdn.net/liweizhao" pos:[23,54] width:352 height:21 align:#left
	label 'lbl39' "Ver 1.0.0" pos:[139,10] width:65 height:16 align:#left
	label 'lbl40' "Step:" pos:[8,82] width:157 height:21 align:#left
	label 'lbl41' "1.assign the original biped part bones" pos:[22,108] width:220 height:21 align:#left
	label 'lbl42' "2.assign the original non-biped custom bones" pos:[22,130] width:220 height:21 align:#left
	label 'lbl43' "3.Create biped and custom bones" pos:[22,151] width:220 height:21 align:#left
	label 'lbl44' "4.select skinMeshes and reskin" pos:[22,172] width:220 height:21 align:#left
	label 'lbl62' "Blog:" pos:[22,56] width:30 height:15 align:#left
)


--boneListWin
rollout BoneListWin "1.Assign BoneList" width:400 height:351
(
	label 'lbl1' "BoneList" pos:[11,11] width:157 height:20 align:#left
	dotNetControl 'boneDataList' "System.Windows.Forms.ListView" pos:[9,30] width:380 height:200 align:#left
	label 'lbl4' "AutoFit:" pos:[39,284] width:77 height:14 align:#left
	label 'lbl5' "original boneRoot:" pos:[37,248] width:97 height:15 align:#left
	label 'selectRootTxt' "UnSelected" pos:[145,249] width:86 height:19 align:#left
	button 'selectAndFitBtn' "SelectAndFit" pos:[149,276] width:159 height:24 align:#left
    
	button 'saveBtn' "Save" pos:[151,308] width:72 height:24 align:#left
	
	
	button 'loadBtn' "Load" pos:[239,308] width:72 height:24 align:#left
	label 'lbl9' "Save And Load:" pos:[38,311] width:115 height:14 align:#left
	button 'selectBtn' "Select" pos:[239,244] width:72 height:24 align:#left
	on BoneListWin open do
	(
	
		boneDataList.Fullrowselect = true
		boneDataList.GridLines = true
	    boneDataList.View = boneDataList.View.Details
	    
	
	    boneDataList.Columns.Add "BoneName" 100
		boneDataList.Columns.Add "MustNeed" 60
	    boneDataList.Columns.Add "SetBone" 200
	    
		InitBoneList()
		for i = 1 to boneInfoDict.count do
		(
			row = dotNetObject "System.Windows.Forms.ListViewItem"
			boneInfoDict[i].SetRow row
	        row.Text = boneInfoDict[i].GetShowName()
	        row.SubItems.Add(boneInfoDict[i].GetMust())
			row.SubItems.Add("")
	        boneDataList.Items.Add(row)
		)
	
	)
	on boneDataList mouseDown arg do
	(
		hit=(boneDataList.HitTest (dotNetObject "System.Drawing.Point" arg.x arg.y))
		local clickName = hit.item.subItems.item[0].text
		local info = GetBoneInfoByName clickName
		if info != undefined then
		(
			if arg.Clicks  == 2 do 
			(
				info.SetSelectBone undefined				
			)
		
			if arg.Clicks  == 1 do 
			(
				info.SetSelectBone $
			)
		)
	)
	on selectAndFitBtn pressed do
	(

		if $ == undefined then
		(
			selectRootTxt.text = "UnSelected"
			selectedBoneRootObj = undefined
		)
		else
		(
			
			if (CheckSelectSingleObj $) == false then
			(
				selectRootTxt.text = "UnSelected"
				selectedBoneRootObj = undefined
				ShowMsg "Please select the biped root only!"
				return 0
			)
			selectedBoneRootObj = $
			selectRootTxt.text = selectedBoneRootObj.name
			SetBipedName selectedBoneRootObj.name
			FitBoneToBiped selectedBoneRootObj
		)
	)
	on saveBtn pressed do
	(
		SaveBoneListFun()
	)
	on loadBtn pressed do
	(
		LoadBoneListFun()
	)
	on selectBtn pressed do
	(
		if $ == undefined then
		(
			selectRootTxt.text = "UnSelected"
			selectedBoneRootObj = undefined
		)
		else
		(
			
			if (CheckSelectSingleObj $) == false then
			(
				selectRootTxt.text = "UnSelected"
				selectedBoneRootObj = undefined
				ShowMsg "Please select the biped root only!"
				return 0
			)
			selectedBoneRootObj = $
			selectRootTxt.text = selectedBoneRootObj.name
			SetBipedName selectedBoneRootObj.name
		)
	)
)


--customBoneListWin
rollout CustomBoneListWin "2.Assign CustomBoneList" width:400 height:324
(
	label 'lbl1' "BoneList(not biped bones)" pos:[11,11] width:157 height:20 align:#left
	dotNetControl 'boneDataList' "System.Windows.Forms.ListView" pos:[9,30] width:380 height:200 align:#left
	label 'lbl5' "boneRoot:" pos:[16,244] width:50 height:15 align:#left
	label 'selectRootTxt' "UnSelected" pos:[81,245] width:86 height:19 align:#left
	button 'selectBtn' "Select And Check" pos:[209,239] width:146 height:24 align:#left 
	
	button 'cleanBtn' "Clean" pos:[209,279] width:147 height:24 align:#left
	button 'addBtn' "Select And Add" pos:[29,278] width:146 height:24 align:#left
	on boneDataList mouseDown arg do
	(
		if arg.Clicks  == 2 do 
		(
			hit=(boneDataList.HitTest (dotNetObject "System.Drawing.Point" arg.x arg.y))
			local clickName = hit.item.subItems.item[0].text
			RemoveCustomBoneInfoByName clickName
		)
		
	)
	on selectBtn pressed do
	(
		if (CheckSelectSingleObj $) == false then
		(
			selectRootTxt.text = "UnSelected"
			selectedBoneRootObj = undefined
			ShowMsg "Please select the biped root only!"
			return 0
		)
		
		selectedBoneRootObj = $
		selectRootTxt.text = selectedBoneRootObj.name
		CheckCustomBone()
	)
	on cleanBtn pressed do
	(
		CleanCustomBone()
	)
	on addBtn pressed do
	(
		AddCustomBoneToList()
	)
)

rollout BoneCtrlWin "3.Bone Controller" width:400 height:249
(
	button 'createBipedBtn' "Create Biped Only" pos:[18,118] width:170 height:36 align:#left
	button 'selectBipedBtn' "SelectBiped" pos:[18,174] width:170 height:36 align:#left
	button 'resizeBtn' "ResizeBones" pos:[214,174] width:170 height:36 align:#left
	label 'lbl1' "Biped Name:" pos:[26,32] width:67 height:17 align:#left
	edittext 'bipedNameTxt' "" pos:[113,27] width:186 height:27 align:#left
	button 'createBoneBtn' "Create Bones Only" pos:[214,117] width:170 height:36 align:#left
	button 'onekeyBtn' "One Key Create" pos:[18,72] width:370 height:36 align:#left

	on createBipedBtn pressed do
	(
		CreateBipedFun()
	)
	on selectBipedBtn pressed do
	(
		if (CheckSelectionIsBipedRoot $) == false then
		(
			selectedBoneRootObj = undefined
			ShowMsg "Please select the biped root only!"
			return 0
		)
		newBipedObj = $
		CheckNewBipedObj()
		
	)
	on resizeBtn pressed do
	(
		ResizeNewBipedFun()
	)
	on createBoneBtn pressed do
	(
		CreateCustomBone()
	)
	on onekeyBtn pressed do
	(
		CreateBipedFun()
		CreateCustomBone()
		ResizeNewBipedFun()
		ResizeNewBipedFun()
	)
)
rollout SkinCtrlWin "4.Skin Controller" width:400 height:320
(
	dotNetControl 'skinDataList' "System.Windows.Forms.ListBox" pos:[9,30] width:380 height:164 align:#left
	label 'lbl32' "Skin Mesh List" pos:[13,8] width:92 height:18 align:#left
	button 'addBtn' "Add" pos:[15,213] width:170 height:31 align:#left
	button 'removeBtn' "Remove" pos:[204,213] width:170 height:31 align:#left
	button 'skinBtn' "ReSkin" pos:[16,272] width:358 height:31 align:#left
	
	
	
	on addBtn pressed do
	(
		AddToSkinMeshList $
	)
	on removeBtn pressed do
	(
		if skinDataList.SelectedItem == undefined then
		(
			ShowMsg "Please select the obj to remove in the ListBox!"
			return 0
		)
		RemoveSkinMeshByName (skinDataList.SelectedItem as string)
	)
	on skinBtn pressed do
	(
		SkinFun()
	)
)
local theFloater = newRolloutFloater "Test" 400 600
addRollout HelpWin theFloater rolledup:false
addRollout BoneListWin theFloater rolledup:true
addRollout CustomBoneListWin theFloater rolledup:true
addRollout BoneCtrlWin theFloater rolledup:true
addRollout SkinCtrlWin theFloater rolledup:true

)
	

Guess you like

Origin blog.csdn.net/liweizhao/article/details/130396339