-- **************************************************
-- Provide Moho with the name of this script object
-- **************************************************

ScriptName = "AE_CalcBoneKeys"

-- **************************************************
-- General information about this script
-- **************************************************

AE_CalcBoneKeys = {}

function AE_CalcBoneKeys:Name()
	return 'Calc and mark bone keyframes'
end

function AE_CalcBoneKeys:Version()
	return '1.0'
end

function AE_CalcBoneKeys:UILabel()
	return 'Calc and mark bone keyframes'
end

function AE_CalcBoneKeys:Creator()
	return 'Alexandra Evseeva'
end

function AE_CalcBoneKeys:Description()
	return ''
end

function AE_CalcBoneKeys:ColorizeIcon()
	return true
end

-- **************************************************
-- Is Relevant / Is Enabled
-- **************************************************

function AE_CalcBoneKeys:IsRelevant(moho)
	return true
end

function AE_CalcBoneKeys:IsEnabled(moho)
	return true
end

-- **************************************************
-- Recurring Values
-- **************************************************

AE_CalcBoneKeys.minMark = 1
AE_CalcBoneKeys.markText = '2'

-- **************************************************
-- Prefs
-- **************************************************

function AE_CalcBoneKeys:LoadPrefs(prefs)
	self.minMark = prefs:GetInt("AE_CalcBoneKeys.minMark", 1)
	self.markText = prefs:GetString("AE_CalcBoneKeys.markText", '2')
end

function AE_CalcBoneKeys:SavePrefs(prefs)
	prefs:SetInt("AE_CalcBoneKeys.minMark", self.minMark)
	prefs:SetString("AE_CalcBoneKeys.markText", self.markText)
end

function AE_CalcBoneKeys:ResetPrefs()
	self.minMark = 1
	self.markText = '2'
end

-- **************************************************
-- AE_CalcBoneKeysDialog
-- **************************************************

local AE_CalcBoneKeysDialog = {}

AE_CalcBoneKeysDialog.TEXT_CONTROL_1 = MOHO.MSG_BASE
AE_CalcBoneKeysDialog.TEXT_CONTROL_2 = MOHO.MSG_BASE + 1

function AE_CalcBoneKeysDialog:new(moho, infoText)
	local d = LM.GUI.SimpleDialog('Calc and mark bone keyframes', AE_CalcBoneKeysDialog)
	local l = d:GetLayout()

	d.dynamicText1Text = LM.GUI.TextList(300, 300)
	l:AddChild(d.dynamicText1Text, LM.GUI.ALIGN_LEFT, 0)
	for i, val in pairs(infoText) do d.dynamicText1Text:AddItem(val) end

	-- Only greater bone numbers will be marked
	d.textControl1Input = LM.GUI.TextControl(0, '1', d.TEXT_CONTROL_1, LM.GUI.FIELD_INT, 'Mark keyframes more then')
	l:AddChild(d.textControl1Input, LM.GUI.ALIGN_LEFT, 0)

	d.textControl2Input = LM.GUI.TextControl(0, '2+', d.TEXT_CONTROL_2, LM.GUI.FIELD_TEXT, 'with the mark of')
	l:AddChild(d.textControl2Input, LM.GUI.ALIGN_LEFT, 0)
	return d
end

function AE_CalcBoneKeysDialog:UpdateWidgets(moho)
	self.textControl1Input:SetValue(AE_CalcBoneKeys.minMark)
	self.textControl2Input:SetValue(AE_CalcBoneKeys.markText)
end

function AE_CalcBoneKeysDialog:OnOK(moho)
	AE_CalcBoneKeys.minMark = self.textControl1Input:IntValue()
	AE_CalcBoneKeys.markText = self.textControl2Input:Value()
end

function AE_CalcBoneKeysDialog:HandleMessage(msg)
	if msg == self.TEXT_CONTROL_1 then
		--print('Message TEXT_CONTROL_1 received')
	elseif msg == self.TEXT_CONTROL_2 then
		--print('Message TEXT_CONTROL_2 received')
	else
		
	end
end


-- **************************************************
-- The guts of this script
-- **************************************************

function AE_CalcBoneKeys:Run(moho)

	self.skel = moho.layer
	if moho:LayerAsBone(moho.layer) then 
		self.skel = moho:LayerAsBone(moho.layer):Skeleton()
	else 
		self.skel = moho.layer:ControllingSkeleton()
	end
	if not self.skel then return LM.GUI.Alert(LM.GUI.ALERT_DANGER, "Can not find any skeleton") end
	
	local infoText = self:GetInfo(moho)

	local dlog = AE_CalcBoneKeysDialog:new(moho, infoText)
	if (dlog:DoModal() == LM.GUI.MSG_CANCEL) then
		return
	end
	
	moho.document:SetDirty()
	moho.document:PrepUndo(nil)
	
	local markerChannel = moho.document.fTimelineMarkers
	for f = 1, markerChannel:Duration() do
		if markerChannel:HasKey(f) and markerChannel:GetValue(f) == self.markText then
			markerChannel:DeleteKey(f)
		end
	end
	
	for f, bones in pairs(self.frameTable) do
		if bones > self.minMark then
			markerChannel:SetValue(f, self.markText)
			local interp = MOHO.InterpSetting:new_local()
			markerChannel:GetKeyInterp(f, interp)
			interp.tags = 5
			markerChannel:SetKeyInterp(f, interp)
		end
	end
	
end

function AE_CalcBoneKeys:GetInfo(moho)
	
	self.frameTable = {}
	local boneTracks = {'fAnimAngle', 'fAnimPos', 'fAnimScale'}
	for f = 1, moho.document:AnimDuration() do
		self.frameTable[f] = 0
		local counter = 0
		for b = 0, self.skel:CountBones() - 1 do
			for _, name in pairs(boneTracks) do
				if self.skel:Bone(b)[name]:HasKey(f) then
					self.frameTable[f] = self.frameTable[f] + 1
					break
				end 
			end
		end
	end
	
	local infoTable = {}
	for _, val in pairs(self.frameTable) do
		if not infoTable[val] then infoTable[val] = 1
		else infoTable[val] = infoTable[val] + 1
		end
	end
	
	self.infoTable = {}
	for i, val in pairs(infoTable) do table.insert(self.infoTable, {bones=i, frames=val}) end
	table.sort (self.infoTable, function (a, b) return (a.bones > b.bones) end)
	
	local returnText = {"Now You have:"}
	for _, val in pairs(self.infoTable) do
		table.insert(returnText, string.format("%s frames with %s bones keyed", val.frames, val.bones))
	end

		
	return returnText
end

Calculate and mark bone keys
Listed

Script type: Button/Menu

Uploaded: Jan 11 2022, 12:20

Mark frames with custom number of bones keyed

Installation Options:

This script, and all other scripts on this site are distributed as free software under the GNU General Public License 3.0 or later.
Downloads count: 33