
--0xACDC0000 See CryHeaders.h 302
struct BONE_ENTITY
(
	BoneID 			= 0,		--int
	ParentID 		= 0,		--int   
	nChildren 		= 0,		--int

	--// Id of controller (CRC32 From name of bone).
	ControllerID 	= 0, --unsigned int
	
	prop 				= #(), --array of char
	prop_length 	= 32,
	
	phys 				= #(), --Compiled Physical Bones --see chunktype 0xACDC0001 --see CryHeaders_info.h 69
	
	_bone			= unsupplied --pie
)

struct create_bones
(
	Create_Bones_Report							= false,
	BONEIDS_ARR_FROM_MESHSUBSET 		= #(),
	SKINBONES_ARRAY								= #(),
	
	fn SET_VERT_WEIGHTS \
										LOADED: \
										LOADEDm: \
										SKINBONES_FROM_0xCCCC0017: =
	(
		local nCount 			= LOADEDm[1].g_MESH_SUBSETS_CHUNK_DESC_0800[1].nCount
		local MeshSubset 	= LOADEDm[1].g_MESH_SUBSETS_CHUNK_DESC_0800[1].MeshSubsetsArr
		--Array, containing a struct per vertex, see CryHeaders.h 135
		local CrySkinVtx		= LOADEDm[1].g_ECgfStreamType[1].CGF_STREAM_BONEMAPPING
		
		--maybe this is not correct all the time, and perhaps this check should be removed
		if nCount == ::g_BUILT_MESHES.count then
		(
			--////////////////////////////////  SET THE REAL WEIGHTS  /////////////////////////////////
			local nFirstVertId 	= 0
			local nNumVerts 		= 0
			
			for m=1 to ::g_BUILT_MESHES.count do
			(
				-------------------------------
				clearSelection() --deselect everything
				-------------------------------
				
				theMesh 	= ::g_BUILT_MESHES[m].mesh
				
				--nVerts = getNumVerts theMesh	--<------- the nVerts (the vert count for each current mesh)
				theSkin 		= ::g_BUILT_MESHES[m].modifiers[1]
				
				-------------------------------
				select ::g_BUILT_MESHES[m] --select only the current looped mesh
				max modify mode --enter modify mode (we must do that inorder to add weights to the skin modifier)
				modPanel.setCurrentObject theSkin --we must set the current skin in the modpanel, else we can't add weights
				
				--// REPORT (a check to see that the modpanel is active and the current modifier is the skin (which we will add weights to)
				local checkmod = modPanel.getCurrentObject()				
				if Create_Bones_Report then ( format "CURRENT: %\n" checkmod )	
				-------------------------------
				
				if iskindof checkmod Skin then
				(
					nBones = skinOps.GetNumberBones theSkin
					
					--example
	-- 				inst_LOADED._chrm[1].g_MESH_SUBSETS_CHUNK_DESC_0800[1].MeshSubsetsArr
	-- 				#((MeshSubset nFirstIndexId:0 nNumIndices:1548 nFirstVertId:0 nNumVerts:461 nMatID:0 fRadius:0.220218 vCenter:[0,0.0233033,0.0161797]))
					
					nFirstVertId 	= MeshSubset[m].nFirstVertId
					nNumVerts 		= MeshSubset[m].nNumVerts
					
					if Create_Bones_Report then
					(
						---------------	---------------	---------------	---------------	
						format "nFirstVertId = %\n" nFirstVertId
						format "nNumVerts = %\n" nNumVerts					
						---------------	---------------	---------------	---------------
						
						--// REPORT
						format "CURRENTLY APPLYING WEIGHTS TO: % Please Wait...\n" ::g_BUILT_MESHES[m].name
					)				
					
					for v=nFirstVertId+1 to ((nFirstVertId)+nNumVerts) do --loop the size of nNumVerts as described in the MeshSubset info (also not, max is not zero based, so we have to add +1 to "v")	
					(
						local BonesIDs_x_4 		= #()
						local Weights_x_4 		= #()			

						i=4						
						while i > 0 do --apply weights backwards, because the zero weights (Representing IDs of 1 in our script) come last in the cgf/chr and they are applied, the last bones are reapplied the wrong value of zero.
						(							
							local bonesIDs = CrySkinVtx[v].idx[i]+1 --our max bones start at 1 and not zero, therefor we must add +1 --the CrySkinVtx structs
							
							if bonesIDs <= nBones then --Note, that if we do not constrain it like this, we could get a boneID out of range (not sure if these are blending modes, perhaps to previous submesh, so we leave them out for now,)
							(									   --This constraint does not seem to affect the weight mapping (these might be blending bones of some sort)
								Append   (BonesIDs_x_4)   (bonesIDs)
											
								--add 4 weights to array
								Append   (Weights_x_4)   (CrySkinVtx[v].w[i]) --the CrySkinVtx structs							
							)
								
							i -= 1			
						)
									
						skinOps.SetVertexWeights theSkin (v) (BonesIDs_x_4) (Weights_x_4)
									
						free BonesIDs_x_4
						free Weights_x_4
					)
				)
			)
		)
	),
	
	fn SET_VERT_WEIGHTS_TO_ZERO \
													LOADED: \
													LOADEDm: =
	(
		--/////////////////////////   Zero out all weights first for all vertices and all meshes  /////////////////////////
		for m=1 to ::g_BUILT_MESHES.count do
		(
			-------------------------------
			clearSelection() --deselect everything
			-------------------------------			
			
			theMesh 				= ::g_BUILT_MESHES[m].mesh		
			nVerts 					= getnumverts ::g_BUILT_MESHES[m].baseobject.mesh	--<------- the nVerts (the vert count for each current mesh)
			theSkin 					= ::g_BUILT_MESHES[m].modifiers[1]
			faceID 					= getFaceMatID theMesh 1 --// get the faceIDs of the current mesh
			
			-------------------------------
			select ::g_BUILT_MESHES[m] --select only the current looped mesh
			max modify mode --enter modify mode (we must do that inorder to add weights to the skin modifier)
			modPanel.setCurrentObject theSkin --we must set the current skin in the modpanel, else we can't add weights
			
			--// REPORT (a check to see that the modpanel is active and the current modifier is the skin (which we will add weights to)
			local checkmod = modPanel.getCurrentObject()			
			if Create_Bones_Report then ( format "CURRENT: %\n" checkmod )			
			-------------------------------
			
			if iskindof checkmod Skin then
			(
				nBones = skinOps.GetNumberBones theSkin
				
				--//---------------------This is the array for applying zero weights before adding the real weights---------------------
				BoneIDIndex = #() --this is the index with the correct BoneIDs NOTE (id-1 because max ids are not zero based)
				for n=1 to nBones do
				(
					Append BoneIDIndex (skinOps.GetBoneIDByListID theSkin n)	
				)
				
				--// fill an array with zero weights to reflect the size of the array that contains the bones for the current skin
				zeroWeights = #()
				for x=1 to BoneIDIndex.count do
				(
					Append zeroWeights (0.0 as float)
				)
				
				if Create_Bones_Report then
				(
					format 		"nVerts: %\n" 		nVerts
					format 		"nBones: %\n" 	nBones
				)
				
				format "CURRENTLY ZEROING OUT VERTICES Please Wait...\n"			
				--/////////////////////   First apply zero weights to ALL verts in current looped mesh   /////////////////////
				--loop the size of nNumVerts as described in the MeshSubset info --all verts for all meshes (the above loop should be used instead)
				for v=1 to nVerts do 
				(
					--remove current weights (zero them out, we want to start with no weights) -- temp off
					skinOps.ReplaceVertexWeights theSkin (v) (BoneIDIndex) (zeroWeights)			
				)
				--------------------------------------------
			)
		)		
		-----------------------------------Now we set the real weights--------------------------------------
		SET_VERT_WEIGHTS \
										LOADED:									LOADED \
										LOADEDm:									LOADEDm \
										SKINBONES_FROM_0xCCCC0017: 	SKINBONES_FROM_0xCCCC0017
	),
	
	fn ADD_BONES_2_SKIN \
									LOADED: \
									LOADEDm: \
									SKINBONES_FROM_0xCCCC0017: \								
									=
	(
		max modify mode
		
		for m=1 to ::g_BUILT_MESHES.count do
		(
			for _mod in ::g_BUILT_MESHES[m].modifiers do
			(
				if classof _mod == skin then
				(
					theSkin = _mod
					modPanel.setCurrentObject theSkin
					
					for i=1 to SKINBONES_FROM_0xCCCC0017.count do
					(
						skinOps.addbone theSkin SKINBONES_FROM_0xCCCC0017[i] 1
					)
				)
			)
		)		
		
		SET_VERT_WEIGHTS_TO_ZERO \
													LOADED:		LOADED \
													LOADEDm:		LOADEDm
	),	
	
	fn GET_0xCCCC0017_SUBSET_BONES \
														LOADED: \
														LOADEDm: \
														=
	(
		--we will store the bones to apply to the skin (these bones are the ids listed in 0xCCCC0017 (note the id from the table in 0xCCCC0017  must be = id+1)
		--so we will have to match the id+1 to the corresponding 1 based index in ::g_BONES_ARRAY !
		SKINBONES_FROM_0xCCCC0017 = #() 
		
		local g_CryBoneDescData_Comp 		= ::_LOADED[1].g_CryBoneDescData_Comp --num bone subsets		
		local MeshBoneSubsetsArr 				= LOADEDm[1].g_MESH_SUBSETS_CHUNK_DESC_0800[1].MeshBoneSubsetsArr
		
		for i=1 to MeshBoneSubsetsArr.count do
		(
			local numBoneIDs 	= MeshBoneSubsetsArr[i].numBoneIDs
			
			for idx=1 to numBoneIDs do
			(
				local theID		= MeshBoneSubsetsArr[i].arrBoneIDs[idx]	
				
				for x=1 to ::g_BONES_ARRAY.count do
				(			
					if x == (theID+1) then --as we wrote above, the id from the 0xCCCC0017 must be incremented with 1, because max is 1 based, whilst CryEngine uses 0 based indices
					(
						Appendifunique SKINBONES_FROM_0xCCCC0017 ::g_BONES_ARRAY[x]._bone --unique because we don't want to add the same bone twice for meshsubset which have merged ranges					
					)
				)
			)
		)		
		
		ADD_BONES_2_SKIN \
										LOADED:									LOADED \
										LOADEDm:									LOADEDm \										
										SKINBONES_FROM_0xCCCC0017:		SKINBONES_FROM_0xCCCC0017		
	),
	
	----Add skin modifier to all SubMeshes
	fn ADD_SKIN_MODIFIER \
										LOADED: \
										LOADEDm: \
										=
	(
		arr = #()
		for m in ::g_BUILT_MESHES do
		(
			if iskindof m Editable_mesh then
			(
				Append arr m
			)
		)

		for m in arr do
		(
			clearselection()
			max modify mode
			select m
			modPanel.addModToSelection (Skin()) ui:on
		)
		
		GET_0xCCCC0017_SUBSET_BONES \
														LOADED:								LOADED \
														LOADEDm:								LOADEDm
	),	

	--This function is for now called in load_cryHeaders_.ms last inside the function: *read_firstData*
	fn CONSTRUCT_BONES \
									LOADED: \
									LOADEDm: =
	(
		if Create_Bones_Report then
		(
			format "We are now inside *%*\n" CONSTRUCT_BONES
		)
		
		local g_CryBoneDescData_Comp = ::_LOADED[1].g_CryBoneDescData_Comp --num bone subsets
		
		if Create_Bones_Report then
		(
			format 	"============ 	g_CryBoneDescData_Comp.count: 	%   ============\n" 		g_CryBoneDescData_Comp.count
		)
		
		for i=1 to g_CryBoneDescData_Comp.count do
		(
			local m_arrBoneName 			= g_CryBoneDescData_Comp[i].m_arrBoneName
			local m_nControllerID			= g_CryBoneDescData_Comp[i].m_nControllerID
			
			local boneDuplicate				= false			
			
			---------------- We check the ControllerID if we have already loaded the bone, and if so, then we exit(?) / continue(?)------------
			--//!< ControllerID is a Unique id of bone (generated from bone name). see CryHeaders.h 256
			for old=1 to ::g_BONES_ARRAY_OLD.count do
			(
				if m_nControllerID == ::g_BONES_ARRAY_OLD[old].ControllerID then
				(
					--Not sure wether we should exit alltogether if we find at least one duplicate, or just continue checking...both seem to work for now...
					boneDuplicate = true
				)
			)
			--------------------------------------------------------------------------------------------------------------------------
			
			if NOT boneDuplicate then
			(
				local m_nOffsetParent 			= g_CryBoneDescData_Comp[i].m_nOffsetParent --//! This bone parent is this[m_nOffsetParent], 0 if the bone is root. Normally this is <= 0.
				local m_nOffsetChildren 		= g_CryBoneDescData_Comp[i].m_nOffsetChildren
				local m_numChildren 			= g_CryBoneDescData_Comp[i].m_numChildren --//! This is 0 if there are no children.			

				if Create_Bones_Report then
				(
					format "\n--i: %--------m_nOffsetParent: % ------m_nOffsetChildren: %-----m_numChildren: %--\n" i m_nOffsetParent m_nOffsetChildren m_numChildren
					format "m_arrBoneName: %\n" m_arrBoneName 
				)
					
				--ParentID
				local BoneParentIDName 		= g_CryBoneDescData_Comp[i+(m_nOffsetParent)].m_arrBoneName
				local BoneParentID 				= (i-1)+(m_nOffsetParent) --CryLink BoneID - m_nOffsetParent (note i-1 since max arrays are not zero based)			
				
				if Create_Bones_Report then
				(					
					format 		"BoneParentIDName: %\n" 	BoneParentIDName				
					format 		"\t\t BoneParentID: %\n" 		BoneParentID 
				)
					
				if m_nOffsetChildren != 0 then
				(			
					--ChildrenID
					local BoneChildrenIDName 	= g_CryBoneDescData_Comp[i+(m_nOffsetChildren)].m_arrBoneName
					local BoneChildrenID 			= (i-1)+(m_nOffsetChildren) --CryLink BoneID - m_nOffsetParent (note i-1 since max arrays are not zero based)
						
					if Create_Bones_Report then
					(				
						format "\t\t\tBoneChildrenIDName: %\n" BoneChildrenIDName
						format "\t\t\t\t\t BoneChildrenIDName: %\n" BoneChildrenID 
					)
				)
				else
				(
					if Create_Bones_Report then
					(				
						format "\t\t\tThere are no children for *%* \n" BoneParentIDName
					)
				)
				
				local boneLength = 0.07	
				local startPos 					= g_CryBoneDescData_Comp[i].m_DefaultB2W[4]
				local endPos 						= (g_CryBoneDescData_Comp[i].m_DefaultB2W[4]) + (boneLength*(normalize g_CryBoneDescData_Comp[i].m_DefaultB2W[1]))
				local zAxis 							= (normalize g_CryBoneDescData_Comp[i].m_DefaultB2W[3])
						
				--	--newBone = bonesys.createbone	       tfm.row4     (tfm.row4 + 0.01 * (normalize tfm.row1))      (normalize tfm.row3)
				local newbone = BoneSys.createBone				(startPos) \
																				(endPos)  \
																				(zAxis)
						
				newBone.name 							= m_arrBoneName --+ "(" + BoneParentIDName + ")"	
					---------------------------------------------------------------------------
					newBone.length 							= 0	--.07 --shaded meshbone (can be set to zero)
					newBone.width 							= 0	--.01 --shaded meshbone (can be set to zero)
					newBone.height 							= 0	--.01 --shaded meshbone (can be set to zero)
					---------------------------------------------------------------------------
				newBone.wirecolor 						= yellow
				newbone.showlinks 						= true
				newBone.setBoneEnable 					false 0
				newBone.pos.controller 				= TCB_position ()
				newBone.rotation.controller 			= TCB_rotation ()
				
				-----------------------------------------Fill the runtime BONE_ENTITY-----------------------------------------------
				inst_BONE_ENTITY = BONE_ENTITY() --create instance of BONE_ENTITY
				
				inst_BONE_ENTITY.BoneID 			= i
				inst_BONE_ENTITY.ParentID 			= BoneParentID
				inst_BONE_ENTITY.nChildren 			= m_numChildren
				inst_BONE_ENTITY.ControllerID 		= m_nControllerID
				
				inst_BONE_ENTITY._bone 				= newBone
				-----------------------------------------------------------------------------------------------------------------------------
				
				Append ::g_BONES_ARRAY inst_BONE_ENTITY
					
				if BoneParentID != 0 then
				(
					newBone.parent = ::g_BONES_ARRAY[BoneParentID+1]._bone			
				)
					
				--Link the root to the MASTER
				if (i == 2) AND (stricmp m_arrBoneName "root") == 0 then --//if i is "root" make "MASTER" parent to "root"
				(
					if g_CryBoneDescData_Comp[i-1].m_arrBoneName == "MASTER" then
					(
						newBone.parent = ::g_BONES_ARRAY[1]._bone
					)
				)
			)
		)
		
		::g_BONES_ARRAY_OLD = deepcopy ::g_BONES_ARRAY
		
		ADD_SKIN_MODIFIER \
										LOADED:		LOADED \
										LOADEDm:		LOADEDm
	)
)