-- ************************************************** -- Provide Moho with the name of this script object -- ************************************************** ScriptName = "AE_TransformBone" -- ************************************************** -- General information about this script -- ************************************************** AE_TransformBone = {} AE_TransformBone.BASE_STR = 2365 function AE_TransformBone:Name() return "Transform Bone" end function AE_TransformBone:Version() return "6.44" end function AE_TransformBone:Description() return "Move bone (hold <shift> to constrain, <alt> to force translation, <ctrl/cmd> to force scale); Press (shift and) '+' to select children" end function AE_TransformBone:Creator() return "Smith Micro Software, Inc. improved by Alexandra Evseeva" end function AE_TransformBone:UILabel() return(MOHO.Localize("/Scripts/Tool/TransformBone/TransformBone=Transform Bone")) end function AE_TransformBone:LoadPrefs(prefs) self.showPath = prefs:GetBool("AE_TransformBone.showPath", true) self.showLabel = prefs:GetBool("AE_TransformBone.showLabel", true) self.smartOnly = prefs:GetBool("AE_TransformBone.smartOnly", false) self.shiftDivide = prefs:GetInt("AE_TransformBone.shiftDivide", 4) self.nonBone = prefs:GetBool("AE_TransformBone.nonBone", false) self.posIncr = prefs:GetFloat("AE_TransformBone.posIncr", 0.1) self.scaleIncr = prefs:GetFloat("AE_TransformBone.scaleIncr", 0.1) self.angleIncr = prefs:GetFloat("AE_TransformBone.angleIncr", 5) self.localNudge = prefs:GetBool("AE_TransformBone.localNudge", false) end function AE_TransformBone:SavePrefs(prefs) prefs:SetBool("AE_TransformBone.showPath", self.showPath) prefs:SetBool("AE_TransformBone.showLabel", self.showLabel) prefs:SetBool("AE_TransformBone.smartOnly", self.smartOnly) prefs:SetInt("AE_TransformBone.shiftDivide", self.shiftDivide) prefs:SetBool("AE_TransformBone.nonBone", self.nonBone) prefs:SetFloat("AE_TransformBone.posIncr", self.posIncr) prefs:SetFloat("AE_TransformBone.scaleIncr", self.scaleIncr) prefs:SetFloat("AE_TransformBone.angleIncr", self.angleIncr) prefs:SetBool("AE_TransformBone.localNudge", self.localNudge) end function AE_TransformBone:ResetPrefs() self.showPath = true self.showLabel = true self.smartOnly = false self.shiftDivide = 4 self.nonBone = false self.posIncr = 0.1 self.scaleIncr = 0.1 self.angleIncr = 5 self.localNudge = false end function AE_TransformBone:NonDragMouseMove() return true -- Call MouseMoved() even if the mouse button is not down end -- ************************************************** -- Recurring values -- ************************************************** AE_TransformBone.dragging = false AE_TransformBone.keyMovement = false AE_TransformBone.mode = 0 -- 0:translate, 1:rotate, 2:scale, 3:manipulate bones AE_TransformBone.numSel = 0 AE_TransformBone.selID = -1 AE_TransformBone.mousePickedID = -1 AE_TransformBone.boneEnd = -1 AE_TransformBone.lastVec = LM.Vector2:new_local() AE_TransformBone.boneChanged = false AE_TransformBone.showPath = true AE_TransformBone.translationFrame = 0 AE_TransformBone.trPathBone = nil AE_TransformBone.TOLERANCE = 10 AE_TransformBone.selectedLayerChanged = false AE_TransformBone.nonBone = false AE_TransformBone.shiftDivide = 4 AE_TransformBone.posIncr = 0.1 AE_TransformBone.scaleIncr = 0.1 AE_TransformBone.angleIncr = 5 AE_TransformBone.localNudge = false AE_TransformBone.indMode = false -- ************************************************** -- The guts of this script -- ************************************************** function AE_TransformBone:IsEnabled(moho) if self.nonBone then self.lastTool = moho:CurrentTool() return true end if moho:CountBones() < 1 then return false end return true end function AE_TransformBone:IsRelevant(moho) if self.nonBone then self.lastTool = moho:CurrentTool() return true else local skel = moho:Skeleton() if (skel == nil) then return false end return true end end function AE_TransformBone:TestMousePoint(moho, mouseEvent) self.trPathBone = nil if (self.keyMovement) then return 0 end local skel = moho:Skeleton() if (skel == nil) then return 1 end if (self.mousePickedID >= 0) then local bone = skel:Bone(self.mousePickedID) if (bone:IsZeroLength()) then if (mouseEvent.altKey) then return 1 -- alt key forces a zero length bone into rotation mode elseif (mouseEvent.ctrlKey) then return 2 end return 0 -- translation by default for zero-length bones end end if (mouseEvent.altKey) then return 0 elseif (mouseEvent.ctrlKey) then return 2 end local markerR = 6 local v = LM.Vector2:new_local() local pt = LM.Point:new_local() local m = LM.Matrix:new_local() moho.layer:GetFullTransform(moho.frame, m, moho.document) -- first test for translation, as it's more common than scaling for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if ((bone.fSelected or i == self.mousePickedID) and not bone.fHidden) then v:Set(bone.fLength * 0.075, 0) if (moho.frame == 0) then bone.fRestMatrix:Transform(v) else bone.fMovedMatrix:Transform(v) end m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < markerR and math.abs(pt.y - mouseEvent.pt.y) < markerR) then return 0 end end end -- next test for scaling for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if ((bone.fSelected or i == self.mousePickedID) and not bone.fHidden) then v:Set(bone.fLength - bone.fLength * 0.075, 0) if (moho.frame == 0) then bone.fRestMatrix:Transform(v) else bone.fMovedMatrix:Transform(v) end m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < markerR and math.abs(pt.y - mouseEvent.pt.y) < markerR) then return 2 end end end -- finally, test for translation by dragging a curve local selCount = 0 local selBone = nil for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if (bone.fSelected) then selCount = selCount + 1 selBone = bone if (selCount > 1) then break end end end if (selCount == 1 and selBone ~= nil and self.showPath) then local translationWhen = -20000 local g = mouseEvent.view:Graphics() local m = LM.Matrix:new_local() local vec = LM.Vector2:new_local() local pt = LM.Point:new_local() local totalTimingOffset = moho.layer:TotalTimingOffset() moho.layer:GetFullTransform(moho.frame, m, moho.document) -- First see if any keyframes were picked for i = 0, selBone.fAnimPos:CountKeys() - 1 do local frame = selBone.fAnimPos:GetKeyWhen(i) vec = selBone.fAnimPos:GetValue(frame) m:Transform(vec) g:WorldToScreen(vec, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.TOLERANCE and math.abs(pt.y - mouseEvent.pt.y) < self.TOLERANCE) then translationWhen = frame self.trPathBone = selBone break end end -- If no keyframes were picked, try picking a random point along the curve. if (translationWhen <= -10000) then local startFrame = selBone.fAnimPos:GetKeyWhen(0) local endFrame = selBone.fAnimPos:Duration() if (endFrame > startFrame) then local oldVec = LM.Vector2:new_local() g:Clear(0, 0, 0, 0) g:SetColor(255, 255, 255) g:BeginPicking(mouseEvent.pt, 4) for frame = startFrame, endFrame do vec = selBone.fAnimPos:GetValue(frame) m:Transform(vec) if (frame > startFrame) then g:DrawLine(oldVec.x, oldVec.y, vec.x, vec.y) end if (g:Pick()) then translationWhen = frame self.trPathBone = selBone break end oldVec:Set(vec) end end end if (translationWhen > -10000) then self.translationFrame = translationWhen return 0 end end -- if no handle was clicked on, default to rotation return 1 end function AE_TransformBone:OnMouseDown(moho, mouseEvent) local skel = moho:Skeleton() if (skel == nil) then return end self.dragging = true self.translationFrame = moho.layerFrame if (self.selID < 0) then self.mode = self:TestMousePoint(moho, mouseEvent) if (moho.frame == 0 and self.mode == 2) then self.mode = 0 end else -- If selID already has a value, then this function is being called by LM_AddBone. -- In that case, the mode has already been determined. self.mode = 0 end if (self.mode == 3) then LM_ManipulateBones:OnMouseDown(moho, mouseEvent) return end self.numSel = moho:CountSelectedBones(true) self.lastVec:Set(mouseEvent.vec) self.boneChanged = false if (self.mode == 0) then self:OnMouseDown_T(moho, mouseEvent) elseif (self.mode == 1) then self:OnMouseDown_R(moho, mouseEvent) else self:OnMouseDown_S(moho, mouseEvent) end self.numSel = moho:CountSelectedBones(true) moho.layer:UpdateCurFrame() moho:UpdateBonePointSelection() mouseEvent.view:DrawMe() moho:UpdateSelectedChannels() if self.indMode then moho.document:PrepMultiUndo() self:StoreChildTransforms(moho) end self.initBone = skel:NearestBone(mouseEvent.vec) if self.initBone > -1 then self.initBone = skel:Bone(self.initBone) else self.initBone = nil end end function AE_TransformBone:OnMouseMoved(moho, mouseEvent) if (self.mode == 3) then LM_ManipulateBones:OnMouseMoved(moho, mouseEvent) return end local skel = moho:Skeleton() if (skel == nil) then return end if (not self.dragging) then if (moho:CountSelectedBones(true) < 2) then self.mousePickedID = mouseEvent.view:PickBone(mouseEvent.pt, mouseEvent.vec, moho.layer, false) else self.mousePickedID = -1 end local mode = self:TestMousePoint(moho, mouseEvent) if (mode == 0) then mouseEvent.view:SetCursor(MOHO.moveCursor) if (self.trPathBone ~= nil) then self.mousePickedID = skel:BoneID(self.trPathBone) end elseif (mode == 2) then mouseEvent.view:SetCursor(MOHO.scaleCursor) else mouseEvent.view:SetCursor(MOHO.rotateCursor) end mouseEvent.view:DrawMe() return end if (self.numSel < 1) then return end if (self.mode == 0) then self:OnMouseMoved_T(moho, mouseEvent) elseif (self.mode == 1) then self:OnMouseMoved_R(moho, mouseEvent) else self:OnMouseMoved_S(moho, mouseEvent) end moho.layer:UpdateCurFrame() mouseEvent.view:DrawMe() if (self.mode ~= 0 or self.boneEnd ~= 1) then self.lastVec:Set(mouseEvent.vec) end if self.indMode then self:RestoreChildTransforms(moho, true) end end function AE_TransformBone:OnMouseUp(moho, mouseEvent) if (self.mode == 3) then LM_ManipulateBones:OnMouseUp(moho, mouseEvent) return end local skel = moho:Skeleton() if (skel == nil) then self.dragging = false return end if (self.mode == 0) then self:OnMouseUp_T(moho, mouseEvent) elseif (self.mode == 1) then self:OnMouseUp_R(moho, mouseEvent) else self:OnMouseUp_S(moho, mouseEvent) end self.selID = -1 self.boneEnd = -1 self.dragging = false if self.indMode then self:RestoreChildTransforms(moho) self.indMode = false self:UpdateWidgets(moho) end end function AE_TransformBone:OnMouseDown_T(moho, mouseEvent) local skel = moho:Skeleton() if (self.selID < 0) then -- If selID already has a value, then this function is being called by LM_AddBone. -- In that case, PrepUndo has already been called, and the bone has been picked. moho.document:PrepUndo(moho.layer, true) moho.document:SetDirty() if (self.numSel > 1) then self.selID = -2 self.boneEnd = 0 elseif (self.trPathBone ~= nil) then self.selID = skel:BoneID(self.trPathBone) else self.selID = mouseEvent.view:PickBone(mouseEvent.pt, mouseEvent.vec, moho.layer, false) end end for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if (moho.frame == 0) then bone.fTempPos:Set(bone.fAnimPos:GetValue(self.translationFrame)) bone.fTempLength = bone.fLength bone.fTempAngle = bone.fAnimAngle:GetValue(moho.layerFrame) else --bone.fTempPos:Set(bone.fPos) bone.fTempPos:Set(bone.fAnimPos:GetValue(self.translationFrame)) end if (self.numSel < 2) then if (i == self.selID) then bone.fSelected = true if (self.boneEnd < 0) then if (moho.frame == 0 and self.trPathBone == nil) then local boneVec = LM.Vector2:new_local() boneVec:Set(0, 0) bone.fRestMatrix:Transform(boneVec) boneVec = boneVec - mouseEvent.startVec local d = boneVec:Mag() self.boneEnd = 0 boneVec:Set(bone.fLength, 0) bone.fRestMatrix:Transform(boneVec) boneVec = boneVec - mouseEvent.startVec if (boneVec:Mag() < d) then self.boneEnd = 1 end else self.boneEnd = 0 end end else bone.fSelected = false end end if (self.translationFrame ~= 0 and bone.fSelected) then self.boneChanged = true bone.fAnimPos:SetValue(self.translationFrame, bone.fTempPos) end end end function AE_TransformBone:OnMouseMoved_T(moho, mouseEvent) local skel = moho:Skeleton() for boneID = 0, skel:CountBones() - 1 do local bone = skel:Bone(boneID) if (bone.fSelected and (not skel:IsAncestorSelected(boneID))) then if (moho.frame == 0) then bone.fAnimPos:SetValue(self.translationFrame, bone.fTempPos) bone.fLength = bone.fTempLength bone.fAnimAngle:SetValue(moho.layerFrame, bone.fTempAngle) self.boneChanged = true else bone.fPos:Set(bone.fTempPos) end skel:UpdateBoneMatrix(boneID) local offset = mouseEvent.vec if (self.boneEnd == 0) then offset = offset - mouseEvent.startVec elseif (self.boneEnd == 1) then offset = offset - self.lastVec end local boneVec = LM.Vector2:new_local() local inverseM = LM.Matrix:new_local() if (self.boneEnd == 0) then -- move the base of the bone local parent = nil boneVec:Set(0, 0) if (bone.fParent >= 0) then parent = skel:Bone(bone.fParent) if (moho.frame == 0) then parent.fRestMatrix:Transform(boneVec) else parent.fMovedMatrix:Transform(boneVec) end end boneVec = boneVec + offset if (parent) then if (moho.frame == 0) then inverseM:Set(parent.fRestMatrix) else inverseM:Set(parent.fMovedMatrix) end inverseM:Invert() inverseM:Transform(boneVec) end if (mouseEvent.shiftKey) then if (math.abs(boneVec.x) > math.abs(boneVec.y)) then boneVec.y = 0 else boneVec.x = 0 end end local v = nil if (moho.frame == 0) then v = bone.fAnimPos:GetValue(self.translationFrame) + boneVec if (parent) then parent.fMovedMatrix:Transform(v) end v = LM_AddBone:SnapBone(moho, mouseEvent, bone, v) if (parent) then inverseM:Set(parent.fMovedMatrix) inverseM:Invert() inverseM:Transform(v) end else v = bone.fPos + boneVec end if (moho.gridOn) then if (parent) then parent.fMovedMatrix:Transform(v) end moho:SnapToGrid(v) if (parent) then inverseM:Set(parent.fMovedMatrix) inverseM:Invert() inverseM:Transform(v) end end bone.fAnimPos:SetValue(self.translationFrame, v) self.boneChanged = true elseif (self.boneEnd == 1) then -- move the tip of the bone boneVec:Set(bone.fLength, 0) bone.fRestMatrix:Transform(boneVec) boneVec = boneVec + offset if (moho.gridOn) then moho:SnapToGrid(boneVec) self.lastVec:Set(boneVec) else self.lastVec:Set(mouseEvent.vec) end inverseM:Set(bone.fRestMatrix) inverseM:Invert() inverseM:Transform(boneVec) local dL = boneVec:Mag() - bone.fLength bone.fLength = bone.fLength + dL local angle = bone.fAnimAngle:GetValue(moho.layerFrame) angle = angle + math.atan2(boneVec.y, boneVec.x) while angle > 2 * math.pi do angle = angle - 2 * math.pi end while angle < 0 do angle = angle + 2 * math.pi end bone.fTempAngle = angle bone.fTempLength = bone.fLength if (mouseEvent.shiftKey) then angle = angle / (math.pi / self.shiftDivide) angle = (math.pi / self.shiftDivide) * LM.Round(angle) end bone.fAnimAngle:SetValue(moho.layerFrame, angle) self.boneChanged = true for i = 0, skel:CountBones() - 1 do bone = skel:Bone(i) if (bone.fParent == boneID) then boneVec:Set(bone.fTempPos) boneVec.x = boneVec.x + dL bone.fAnimPos:SetValue(moho.layerFrame, boneVec) end end end end -- if bone selected end -- for all bones end function AE_TransformBone:OnMouseUp_T(moho, mouseEvent) local skel = moho:Skeleton() if (self.numSel > 0 or self.boneChanged) then --for i = 0, skel:CountBones() - 1 do -- bone = skel:Bone(i) -- if (bone.fSelected and (not skel:IsAncestorSelected(i))) then -- bone.fAnimPos:SetValue(moho.layerFrame, bone.fPos) -- end --end moho.layer:UpdateCurFrame() if (self.boneChanged) then if (self.translationFrame == moho.layerFrame) then moho:NewKeyframe(CHANNEL_BONE_T) else moho:UpdateUI() end end if MOHO.MohoGlobals.EditMultipleKeys then for b=0, skel:CountBones()-1 do local nextBone = skel:Bone(b) if nextBone.fSelected then --print(nextBone.fTempPos.x, ", ", nextBone.fTempPos.y) --print(nextBone.fPos.x, ", ", nextBone.fPos.y) local diffValue = nextBone.fPos - nextBone.fTempPos for k = 0, nextBone.fAnimPos:CountKeys()-1 do local keyWhen = nextBone.fAnimPos:GetKeyWhen(k) if keyWhen ~= self.translationFrame and nextBone.fAnimPos:IsKeySelected(keyWhen) then local newValue = nextBone.fAnimPos:GetValue(keyWhen) + diffValue nextBone.fAnimPos:SetValue(keyWhen, newValue) end end end end end end end function AE_TransformBone:OnMouseDown_R(moho, mouseEvent) local skel = moho:Skeleton() moho.document:PrepUndo(moho.layer, true) moho.document:SetDirty() if (moho:CountSelectedBones(true) < 2) then for i = 0, skel:CountBones() - 1 do skel:Bone(i).fSelected = false end local id = mouseEvent.view:PickBone(mouseEvent.pt, mouseEvent.vec, moho.layer, false) skel:Bone(id).fSelected = true end local selCount = 0 for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if (bone.fSelected) then self.selID = i selCount = selCount + 1 if (moho.frame == 0) then bone.fTempPos:Set(bone.fAnimPos:GetValue(moho.layerFrame)) bone.fTempLength = bone.fLength bone.fTempAngle = bone.fAnimAngle:GetValue(moho.layerFrame) else self.boneChanged = true bone.fTempAngle = bone.fAnimAngle:GetValue(moho.layerFrame)--bone.fAngle bone.fAnimAngle:SetValue(moho.layerFrame, bone.fTempAngle) end end end if (selCount > 1) then self.selID = -1 end if MOHO.MohoGlobals.EditMultipleKeys then self.tempAngles = {} for i = 0, skel:CountBones() - 1 do if skel:Bone(i).fSelected then local bone = skel:Bone(i) self.tempAngles[i] = bone.fAngle end end end end function AE_TransformBone:OnMouseMoved_R(moho, mouseEvent) local riggingFrame = 0 local skel = moho:Skeleton() for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if (bone.fSelected) then if (moho.frame == 0) then bone.fAnimPos:SetValue(moho.layerFrame, bone.fTempPos) bone.fLength = bone.fTempLength bone.fAnimAngle:SetValue(moho.layerFrame, bone.fTempAngle) self.boneChanged = true else bone.fAngle = bone.fTempAngle end end end skel:UpdateBoneMatrix() for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if (bone.fSelected) then local origin = LM.Vector2:new_local() origin:Set(0, 0) if (moho:CountSelectedBones(true) < 2) then if (moho.frame == 0) then bone.fRestMatrix:Transform(origin) else bone.fMovedMatrix:Transform(origin) end else if self.initBone then if (moho.frame == 0) then self.initBone.fRestMatrix:Transform(origin) else self.initBone.fMovedMatrix:Transform(origin) end else origin = moho.layer:Origin() end end local v1 = self.lastVec - origin local v2 = mouseEvent.vec - origin local angleSign = 1.0 if (not bone.fFixedAngle) then angleSign = bone:ParentalFlipFactor() end v2:Rotate(-math.atan2(v1.y, v1.x)) if (moho.frame == 0) then local angle = bone.fAnimAngle:GetValue(moho.layerFrame) + math.atan2(v2.y, v2.x) * angleSign bone.fAnimAngle:SetValue(moho.layerFrame, angle) self.boneChanged = true else if bone.fFixedAngle and skel:Bone(bone.fParent) and skel:Bone(bone.fParent).fSelected then bone.fAngle = bone.fAnimAngle.value end bone.fAngle = bone.fAngle + math.atan2(v2.y, v2.x) * angleSign end if (moho.frame == 0) then local angle = bone.fAnimAngle:GetValue(moho.layerFrame) while angle > 2 * math.pi do angle = angle - 2 * math.pi end while angle < 0 do angle = angle + 2 * math.pi end bone.fTempAngle = angle if (mouseEvent.shiftKey) then angle = angle / (math.pi / self.shiftDivide) angle = (math.pi / self.shiftDivide) * LM.Round(angle) end bone.fAnimAngle:SetValue(moho.layerFrame, angle) self.boneChanged = true else bone.fTempAngle = bone.fAngle if (mouseEvent.shiftKey) then bone.fAngle = bone.fAngle / (math.pi / self.shiftDivide) bone.fAngle = (math.pi / self.shiftDivide) * LM.Round(bone.fAngle) end bone.fAnimAngle:SetValue(moho.layerFrame, bone.fAngle) self.boneChanged = true if (bone.fConstraints and (not bone.fFixedAngle)) then local min = bone.fAnimAngle:GetValue(riggingFrame) local max = min + bone.fMaxConstraint min = min + bone.fMinConstraint bone.fAngle = LM.Clamp(bone.fAngle, min, max) bone.fAnimAngle:SetValue(moho.layerFrame, bone.fAngle) end moho.layer:UpdateCurFrame() end bone.fAngle = bone.fAnimAngle.value if (moho.frame ~= 0 and (not bone.fFixedAngle)) then if (bone.fConstraints) then local min = bone.fAnimAngle:GetValue(riggingFrame) local max = min + bone.fMaxConstraint min = min + bone.fMinConstraint bone.fAngle = LM.Clamp(bone.fAngle, min, max) end end end end end function AE_TransformBone:OnMouseUp_R(moho, mouseEvent) local skel = moho:Skeleton() --if ((moho.frame > 0) and (moho:CountSelectedBones(true) > 0)) then if (moho:CountSelectedBones(true) > 0) then --for i = 0, skel:CountBones() - 1 do -- local bone = skel:Bone(i) -- if (bone.fSelected) then -- bone.fAnimAngle:SetValue(moho.layerFrame, bone.fAngle) -- end --end moho.layer:UpdateCurFrame() if (self.boneChanged) then moho:NewKeyframe(CHANNEL_BONE) end if MOHO.MohoGlobals.EditMultipleKeys then for b=0, skel:CountBones()-1 do local nextBone = skel:Bone(b) if nextBone.fSelected then local diffValue = nextBone.fAngle - self.tempAngles[b] for k = 1, nextBone.fAnimAngle:CountKeys()-1 do local keyWhen = nextBone.fAnimAngle:GetKeyWhen(k) if keyWhen ~= self.translationFrame and nextBone.fAnimAngle:IsKeySelected(keyWhen) then local newValue = nextBone.fAnimAngle:GetValue(keyWhen) + diffValue nextBone.fAnimAngle:SetValue(keyWhen, newValue) end end end end end end end function AE_TransformBone:OnMouseDown_S(moho, mouseEvent) local skel = moho:Skeleton() moho.document:PrepUndo(moho.layer, true) moho.document:SetDirty() if (moho:CountSelectedBones(true) < 2) then for i = 0, skel:CountBones() - 1 do skel:Bone(i).fSelected = false end local id = mouseEvent.view:PickBone(mouseEvent.pt, mouseEvent.vec, moho.layer, false) skel:Bone(id).fSelected = true end for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if (bone.fSelected) then if (moho.frame == 0) then bone.fTempScale = bone.fAnimScale:GetValue(moho.layerFrame) else self.boneChanged = true bone.fTempScale = bone.fAnimScale:GetValue(moho.layerFrame)--bone.fScale bone.fAnimScale:SetValue(moho.layerFrame, bone.fTempScale) end end end end function AE_TransformBone:OnMouseMoved_S(moho, mouseEvent) local skel = moho:Skeleton() for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if (bone.fSelected) then local scaleFactor = (mouseEvent.pt.x - mouseEvent.startPt.x) / 100 if (scaleFactor < 0) then scaleFactor = 1 / (-scaleFactor + 1) else scaleFactor = scaleFactor + 1 end bone.fScale = bone.fTempScale * scaleFactor bone.fAnimScale:SetValue(moho.layerFrame, bone.fScale) self.boneChanged = true end end end function AE_TransformBone:OnMouseUp_S(moho, mouseEvent) local skel = moho:Skeleton() if ((moho.frame > 0) and (moho:CountSelectedBones(true) > 0)) then --for i = 0, skel:CountBones() - 1 do -- local bone = skel:Bone(i) -- if (bone.fSelected) then -- bone.fAnimScale:SetValue(moho.layerFrame, bone.fScale) -- end --end moho.layer:UpdateCurFrame() if (self.boneChanged) then moho:NewKeyframe(CHANNEL_BONE_S) end end end function AE_TransformBone:OnKeyDown(moho, keyEvent) if self.localNudge and self:KeyIncrements(moho, keyEvent) then keyEvent.view:DrawMe() return end if keyEvent.key == "f" and keyEvent.altKey then if self.freezeMode then self.freezeMode = false else self.freezeMode = true end return end local skel = moho:Skeleton() if (skel == nil) then return end if ((keyEvent.keyCode == LM.GUI.KEY_DELETE) or (keyEvent.keyCode == LM.GUI.KEY_BACKSPACE)) then local names2delete = {} local actions2delete = {} for b=0, skel:CountBones()-1 do local nextBone = skel:Bone(b) if nextBone.fSelected then local name = nextBone:Name() table.insert(names2delete, name) -- find smartbone actions for a=0, moho.layer:CountActions()-1 do local actionName = moho.layer:ActionName(a) if string.find(actionName, "^"..name.."$") or string.find(actionName, "^"..name.." 2$")then table.insert(actions2delete, actionName) elseif string.find(actionName, "^"..name.."[-]?%d+|") or string.find(actionName, "|"..name.."[-]?%d+$") then table.insert(actions2delete, actionName) table.insert(names2delete, actionName) end end end end for i, nextAction in pairs(actions2delete) do if moho.layer:HasAction(nextAction) then moho.layer:DeleteAction(nextAction) end end end LM_SelectBone:OnKeyDown(moho, keyEvent) if keyEvent.key == "+" or keyEvent.key == "=" then --select all direct children local inDirectChildren = keyEvent.shiftKey -- all the children tree local parents = {} local children = {} for i = 0, skel:CountBones() - 1 do if (skel:Bone(i).fSelected) then table.insert(parents, i) end end for i = 0, skel:CountBones() - 1 do for j,b in pairs(parents) do if (inDirectChildren and skel:IsBoneChild(b,i)) or skel:Bone(i).fParent == b then table.insert(children, i) end end end if #children > 0 then if not inDirectChildren then for k,v in pairs(parents) do skel:Bone(v).fSelected = false end end for k,v in pairs(children) do skel:Bone(v).fSelected = true end moho:UpdateBonePointSelection() keyEvent.view:DrawMe() moho:UpdateSelectedChannels() end end if (keyEvent.ctrlKey) then local inc = 1 if (keyEvent.shiftKey) then inc = 10 end local m = LM.Matrix:new_local() moho.layer:GetFullTransform(moho.frame, m, moho.document) local fakeME = {} fakeME.view = keyEvent.view fakeME.pt = LM.Point:new_local() fakeME.pt:Set(keyEvent.view:Graphics():Width() / 2, keyEvent.view:Graphics():Height() / 2) fakeME.startPt = LM.Point:new_local() fakeME.startPt:Set(fakeME.pt) fakeME.vec = keyEvent.view:Point2Vec(fakeME.pt, m) fakeME.startVec = keyEvent.view:Point2Vec(fakeME.pt, m) fakeME.shiftKey = false fakeME.ctrlKey = false fakeME.altKey = keyEvent.altKey fakeME.penPressure = 0 self.keyMovement = true if (keyEvent.keyCode == LM.GUI.KEY_UP) then self.selID = self:SelIDForNudge(moho, skel) self:OnMouseDown(moho, fakeME) self.boneEnd = 0 fakeME.pt.y = fakeME.pt.y - inc fakeME.vec = keyEvent.view:Point2Vec(fakeME.pt, m) self:OnMouseMoved(moho, fakeME) self:OnMouseUp(moho, fakeME) elseif (keyEvent.keyCode == LM.GUI.KEY_DOWN) then self.selID = self:SelIDForNudge(moho, skel) self:OnMouseDown(moho, fakeME) self.boneEnd = 0 fakeME.pt.y = fakeME.pt.y + inc fakeME.vec = keyEvent.view:Point2Vec(fakeME.pt, m) self:OnMouseMoved(moho, fakeME) self:OnMouseUp(moho, fakeME) elseif (keyEvent.keyCode == LM.GUI.KEY_LEFT) then self.selID = self:SelIDForNudge(moho, skel) self:OnMouseDown(moho, fakeME) self.boneEnd = 0 fakeME.pt.x = fakeME.pt.x - inc fakeME.vec = keyEvent.view:Point2Vec(fakeME.pt, m) self:OnMouseMoved(moho, fakeME) self:OnMouseUp(moho, fakeME) elseif (keyEvent.keyCode == LM.GUI.KEY_RIGHT) then self.selID = self:SelIDForNudge(moho, skel) self:OnMouseDown(moho, fakeME) self.boneEnd = 0 fakeME.pt.x = fakeME.pt.x + inc fakeME.vec = keyEvent.view:Point2Vec(fakeME.pt, m) self:OnMouseMoved(moho, fakeME) self:OnMouseUp(moho, fakeME) end self.keyMovement = false end end function AE_TransformBone:DrawMe(moho, view) if self.nonBone then local skel = moho:Skeleton() if (skel == nil) then if moho:CurrentTool() ~= self.lastTool then local boneLayer = moho.layer:ControllingBoneLayer() if boneLayer then moho:SetSelLayer(boneLayer) end end end self.lastTool = moho:CurrentTool() end if ((self.dragging or moho:IsPlaying()) and not self.showPath) then return end local skel = moho:Skeleton() if (skel == nil) then return end local markerR = 6 local v = LM.Vector2:new_local() local g = view:Graphics() local layerMatrix = LM.Matrix:new_local() local vc1 = LM.ColorVector:new_local() local vc2 = LM.ColorVector:new_local() local interp = MOHO.InterpSetting:new_local() vc1:Set(MOHO.MohoGlobals.SelCol) vc2:Set(MOHO.MohoGlobals.BackCol) --vc1 = (vc1 * 3 + vc2 * 4) / 7 vc1 = (vc1 + vc2) / 2 local fillCol = vc1:AsColorStruct() moho.layer:GetFullTransform(moho.frame, layerMatrix, moho.document) g:Push() g:ApplyMatrix(layerMatrix) g:SetSmoothing(true) g:SetBezierTolerance(2) for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if (bone.fSelected and self.showPath) then --and bone.fParent < 0) then -- draw path --local startFrame = bone.fAnimPos:GetKeyWhen(0) --local endFrame = bone.fAnimPos:Duration() local totalTimingOffset = moho.layer:TotalTimingOffset() local startFrame = moho.document:StartFrame() + totalTimingOffset local endFrame = moho.document:EndFrame() + totalTimingOffset --[[ if (startFrame - totalTimingOffset < 0) then startFrame = totalTimingOffset end --]] if MOHO.MohoGlobals.PlayStart > 0 then startFrame = MOHO.MohoGlobals.PlayStart + totalTimingOffset end if MOHO.MohoGlobals.PlayEnd > 0 then endFrame = MOHO.MohoGlobals.PlayEnd + totalTimingOffset end --[[ bone.fAnimPos:GetKeyInterp(endFrame, interp) if (interp:IsAdditiveCycle()) then endFrame = moho.document:EndFrame() + totalTimingOffset end --]] if (endFrame > startFrame) then local vec = LM.Vector2:new_local() local oldVec = LM.Vector2:new_local() g:SetColor(102, 152, 203) for frame = startFrame, endFrame do --vec = bone.fAnimPos:GetValue(frame) vec = AE_Utilities:GetGlobalBonePos(moho, skel, bone, frame) if (frame > startFrame) then g:DrawLine(oldVec.x, oldVec.y, vec.x, vec.y) end if (bone.fAnimPos:HasKey(frame)) then g:DrawFatMarker(vec.x, vec.y, 5) else g:DrawMarker(vec.x, vec.y) end oldVec:Set(vec) end end end if (((bone.fSelected and self.mousePickedID == -1) or i == self.mousePickedID) and not bone.fHidden) then -- draw handles if (not (self.dragging or moho:IsPlaying())) then v:Set(bone.fLength - bone.fLength * 0.075, 0) if (moho.frame == 0) then bone.fRestMatrix:Transform(v) else bone.fMovedMatrix:Transform(v) end g:SetColor(fillCol) g:FillCirclePixelRadius(v, markerR) g:SetColor(MOHO.MohoGlobals.SelCol) g:FrameCirclePixelRadius(v, markerR) if (not bone:IsZeroLength()) then v:Set(bone.fLength * 0.075, 0) if (moho.frame == 0) then bone.fRestMatrix:Transform(v) else bone.fMovedMatrix:Transform(v) end g:SetColor(fillCol) g:FillCirclePixelRadius(v, markerR) g:SetColor(MOHO.MohoGlobals.SelCol) g:FrameCirclePixelRadius(v, markerR) end v:Set(bone.fLength * 0.5, 0.05/g:CurrentScale()) if (moho.frame == 0) then bone.fRestMatrix:Transform(v) else bone.fMovedMatrix:Transform(v) end if self.showLabel then HV_Font:DrawLetters(moho, g, bone:Name(), 5/g:CurrentScale(), v.x, v.y) end end end end g:Pop() end function AE_TransformBone:SelIDForNudge(moho, skel) for i = 0, skel:CountBones() - 1 do if (skel:Bone(i).fSelected) then return i end end return -1 end function AE_TransformBone:FlipBones(moho, skel, horizontal) if (moho:CountSelectedBones(true) < 1) then return end if (moho.layerFrame == 0) then -- flip on rigging frame moho.document:PrepUndo(moho.layer, true) moho.document:SetDirty() for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if (bone.fSelected) then skel:FlipBone(i, horizontal) end end moho.layer:UpdateCurFrame() else -- animation flip moho.document:PrepUndo(moho.layer, true) moho.document:SetDirty() for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if (bone.fSelected) then if (horizontal) then bone.fFlipH:SetValue(moho.layerFrame, not bone.fFlipH.value) else bone.fFlipV:SetValue(moho.layerFrame, not bone.fFlipV.value) end end end moho.layer:UpdateCurFrame() if (horizontal) then moho:NewKeyframe(CHANNEL_BONE_FLIPH) else moho:NewKeyframe(CHANNEL_BONE_FLIPV) end end end -- ************************************************** -- Tool options - create and respond to tool's UI -- ************************************************** AE_TransformBone.CHANGE_T_X = MOHO.MSG_BASE AE_TransformBone.CHANGE_T_Y = MOHO.MSG_BASE + 1 AE_TransformBone.RESET_T = MOHO.MSG_BASE + 2 AE_TransformBone.CHANGE_L = MOHO.MSG_BASE + 3 AE_TransformBone.CHANGE_S = MOHO.MSG_BASE + 4 AE_TransformBone.RESET_S = MOHO.MSG_BASE + 5 AE_TransformBone.CHANGE_R = MOHO.MSG_BASE + 6 AE_TransformBone.RESET_R = MOHO.MSG_BASE + 7 AE_TransformBone.SHOW_PATHS = MOHO.MSG_BASE + 8 AE_TransformBone.FLIP_H = MOHO.MSG_BASE + 9 AE_TransformBone.FLIP_V = MOHO.MSG_BASE + 10 AE_TransformBone.DUMMY = MOHO.MSG_BASE + 11 AE_TransformBone.SELECTITEM = MOHO.MSG_BASE + 30 AE_TransformBone.SMARTONLYCHECK = MOHO.MSG_BASE + 12 AE_TransformBone.SETTINGSBUTTON = MOHO.MSG_BASE + 13 AE_TransformBone.NONEBONE = MOHO.MSG_BASE + 15 AE_TransformBone.localNudge = MOHO.MSG_BASE + 16 AE_TransformBone.SHOW_LABELS = MOHO.MSG_BASE + 17 AE_TransformBone.INDMODE = MOHO.MSG_BASE + 18 -- ************************************************** -- IncrDialog -- ************************************************** local IncrDialog = {} IncrDialog.POSINCRINPUT = MOHO.MSG_BASE + 20 IncrDialog.ANGLEINCRINPUT = MOHO.MSG_BASE + 21 IncrDialog.SCALEINCRINPUT = MOHO.MSG_BASE + 22 IncrDialog.SHIFTDIVIDE = MOHO.MSG_BASE + 14 IncrDialog.LOCALNUDGE = MOHO.MSG_BASE + 23 function IncrDialog:new() local d = LM.GUI.SimpleDialog('', IncrDialog) local l = d:GetLayout() d.posIncrInput = LM.GUI.TextControl(0, '0.1', d.POSINCRINPUT, LM.GUI.FIELD_FLOAT, 'Position increment') l:AddChild(d.posIncrInput, LM.GUI.ALIGN_LEFT, 0) d.scaleIncrInput = LM.GUI.TextControl(0, '0.1', d.SCALEINCRINPUT, LM.GUI.FIELD_FLOAT, 'Scale increment') l:AddChild(d.scaleIncrInput, LM.GUI.ALIGN_LEFT, 0) d.angleIncrInput = LM.GUI.TextControl(0, '0.1', d.ANGLEINCRINPUT, LM.GUI.FIELD_FLOAT, 'Angle increment') l:AddChild(d.angleIncrInput, LM.GUI.ALIGN_LEFT, 0) d.shiftDivideText = LM.GUI.TextControl(0, "00", d.SHIFTDIVIDE, LM.GUI.FIELD_INT, "On Shift:") l:AddChild(d.shiftDivideText) d.shiftDivideText:SetToolTip("180°/x = shift-rotate increment") d.localNudgeChk = LM.GUI.CheckBox("Local nudge bones", d.LOCALNUDGE) l:AddChild(d.localNudgeChk) return d end function IncrDialog:UpdateWidgets(moho) self.posIncrInput:SetValue(AE_TransformBone.posIncr) self.scaleIncrInput:SetValue(AE_TransformBone.scaleIncr) self.angleIncrInput:SetValue(AE_TransformBone.angleIncr) self.shiftDivideText:SetValue(AE_TransformBone.shiftDivide) self.localNudgeChk:SetValue(AE_TransformBone.localNudge) end function IncrDialog:OnOK(moho) AE_TransformBone.posIncr = self.posIncrInput:FloatValue() AE_TransformBone.textX:SetWheelInc(AE_TransformBone.posIncr) AE_TransformBone.textY:SetWheelInc(AE_TransformBone.posIncr) AE_TransformBone.scaleIncr = self.scaleIncrInput:FloatValue() AE_TransformBone.angle:SetWheelInc(AE_TransformBone.angleIncr) AE_TransformBone.angleIncr = self.angleIncrInput:FloatValue() AE_TransformBone.angle:SetWheelInc(AE_TransformBone.angleIncr) AE_TransformBone.shiftDivide = math.max(self.shiftDivideText:IntValue(), 1) AE_TransformBone.localNudge = self.localNudgeChk:Value() end function IncrDialog:HandleMessage(msg) if msg == self.SHIFTDIVIDE then if self.shiftDivideText:IntValue() < 1 then self.shiftDivideText:SetValue(1) end else end end -- ************************************************** function AE_TransformBone:DoLayout(moho, layout) self.menu = LM.GUI.Menu(MOHO.Localize("/Scripts/Tool/TransformBone/SelectBone=Select Bone")) self.popup = LM.GUI.PopupMenu(120, false) self.popup:SetMenu(self.menu) layout:AddChild(self.popup) self.smartonlyCheck = LM.GUI.CheckBox("SM", self.SMARTONLYCHECK) layout:AddChild(self.smartonlyCheck) self.smartonlyCheck:SetToolTip("Show only smartbones in select pop-up") layout:AddChild(LM.GUI.StaticText("Pos:")) self.textX = LM.GUI.TextControl(0, "00.000", self.CHANGE_T_X, LM.GUI.FIELD_FLOAT, MOHO.Localize("/Scripts/Tool/TransformBone/X=X:")) self.textX:SetWheelInc(self.posIncr) layout:AddChild(self.textX) self.textY = LM.GUI.TextControl(0, "00.000", self.CHANGE_T_Y, LM.GUI.FIELD_FLOAT, MOHO.Localize("/Scripts/Tool/TransformBone/Y=Y:")) self.textY:SetWheelInc(self.posIncr) layout:AddChild(self.textY) self.textL = LM.GUI.TextControl(0, "00.000", self.CHANGE_L, LM.GUI.FIELD_UFLOAT, "L:") self.textL:SetWheelInc(0.1) layout:AddChild(self.textL) self.resetT = LM.GUI.Button("R", self.RESET_T) layout:AddChild(self.resetT) self.resetT:SetToolTip("Reset translate") self.scale = LM.GUI.TextControl(0, "00.000", self.CHANGE_S, LM.GUI.FIELD_FLOAT, MOHO.Localize("/Scripts/Tool/TransformBone/Scale=Scale:")) self.scale:SetWheelInc(self.scaleIncr) layout:AddChild(self.scale) self.resetS = LM.GUI.Button("R", self.RESET_S) layout:AddChild(self.resetS) self.resetS:SetToolTip("Reset scale") self.angle = LM.GUI.TextControl(0, "000.000", self.CHANGE_R, LM.GUI.FIELD_FLOAT, MOHO.Localize("/Scripts/Tool/TransformBone/Angle=Angle:")) self.angle:SetWheelInc(self.angleIncr) layout:AddChild(self.angle) self.resetR = LM.GUI.Button("R", self.RESET_R) layout:AddChild(self.resetR) self.resetR:SetToolTip("Reset angle") self.pathCheck = LM.GUI.CheckBox("Path", self.SHOW_PATHS) layout:AddChild(self.pathCheck) self.labelCheck = LM.GUI.CheckBox("Label", self.SHOW_LABELS) layout:AddChild(self.labelCheck) if (MOHO.IsMohoPro()) then layout:AddChild(LM.GUI.ImageButton("ScriptResources/flip_bone_h", MOHO.Localize("/Scripts/Tool/TransformBone/EndFlip=End Flip"), false, self.FLIP_H, true)) layout:AddChild(LM.GUI.ImageButton("ScriptResources/flip_bone_v", MOHO.Localize("/Scripts/Tool/TransformBone/SideFlip=Side Flip"), false, self.FLIP_V, true)) end self.indModeCheck = LM.GUI.ImageButton("ScriptResources/fixed_handles", "Transform independently", true, self.INDMODE, true) layout:AddChild(self.indModeCheck) self.dlog = IncrDialog:new() self.Popup = LM.GUI.PopupDialog('...', false, 0) self.Popup:SetDialog(self.dlog) layout:AddChild(self.Popup, LM.GUI.ALIGN_LEFT, 0) self.Popup:SetToolTip('Set increments') --[[ --TODO: fix DrawMe behavior, handle Mouse presses and uncomment self.nonBoneCheck = LM.GUI.CheckBox("With non-bone", self.NONEBONE) layout:AddChild(self.nonBoneCheck) self.nonBoneCheck:SetToolTip("Use with non-bone layers") --]] end function AE_TransformBone:UpdateWidgets(moho) local skel = moho:Skeleton() if (skel == nil) then return end local selID = skel:SelectedBoneID() MOHO.BuildBoneMenu(self.menu, skel, self.SELECTITEM, self.DUMMY) if not self.smartOnly then MOHO.BuildBoneMenu(self.menu, skel, self.SELECTITEM, self.DUMMY) else self.menu:RemoveAllItems() local smartBoneList = {} for b=0, skel:CountBones()-1 do local bone = skel:Bone(b) if self:IsASmartBone(moho, skel, bone) then table.insert(smartBoneList, {ID = b, name = bone:Name()}) end end if #smartBoneList > 0 then table.sort(smartBoneList, function(a,b) return string.lower(a.name) < string.lower(b.name) end) for k,v in pairs(smartBoneList) do self.menu:AddItem(v.name, 0, self.SELECTITEM + v.ID) end end end if (selID >= 0) then local bone = skel:Bone(selID) self.textX:SetValue(bone.fPos.x) self.textY:SetValue(bone.fPos.y) self.textL:SetValue(bone.fLength) else self.textX:SetValue("") self.textY:SetValue("") self.textL:SetValue("") end if (moho:CountSelectedBones(true) > 0) then local selCount = 0 local scale = 0 for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if (bone.fSelected) then selCount = selCount + 1 scale = scale + bone.fScale end end self.scale:SetValue(scale / selCount) else self.scale:SetValue("") end if (moho:CountSelectedBones(true) > 0) then local selCount = 0 local angle = 0 for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if (bone.fSelected) then selCount = selCount + 1 angle = angle + bone.fAngle end end self.angle:SetValue(math.deg(angle) / selCount) else self.angle:SetValue("") end if (moho.frame == 0) then self.textL:Enable(true) self.scale:Enable(false) self.resetT:Enable(false) self.resetS:Enable(false) self.resetR:Enable(false) else self.textL:Enable(false) self.scale:Enable(true) self.resetT:Enable(true) self.resetS:Enable(true) self.resetR:Enable(true) end self.pathCheck:SetValue(self.showPath) self.smartonlyCheck:SetValue(self.smartOnly) --self.nonBoneCheck:SetValue(self.nonBone) self.labelCheck:SetValue(self.showLabel) if moho.frame == 0 then self.indMode = false self.indModeCheck:Enable(false) else self.indModeCheck:Enable(true) end self.indModeCheck:SetValue(self.indMode) end function AE_TransformBone:HandleMessage(moho, view, msg) local skel = moho:Skeleton() if (skel == nil) then return end if (msg == self.RESET_T) then if (moho:CountSelectedBones(true) > 0) then moho.document:PrepUndo(moho.layer, true) moho.document:SetDirty() for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if (bone.fSelected) then bone.fAnimPos:SetValue(moho.layerFrame, bone.fAnimPos:GetValue(0)) end end moho.layer:UpdateCurFrame() moho:NewKeyframe(CHANNEL_BONE_T) self:UpdateWidgets(moho) end elseif (msg == self.CHANGE_T_X) then self:ChangePosX(moho) elseif (msg == self.CHANGE_T_Y) then self:ChangePosY(moho) elseif (msg == self.CHANGE_L) then if (moho:CountSelectedBones(true) > 0) then moho.document:PrepUndo(moho.layer, true) moho.document:SetDirty() for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if (bone.fSelected) then bone.fLength = self.textL:FloatValue() end end moho.layer:UpdateCurFrame() moho:NewKeyframe(CHANNEL_BONE) end elseif (msg == self.RESET_S) then if (moho:CountSelectedBones(true) > 0) then moho.document:PrepUndo(moho.layer, true) moho.document:SetDirty() for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if (bone.fSelected) then bone.fAnimScale:SetValue(moho.layerFrame, bone.fAnimScale:GetValue(0)) end end moho.layer:UpdateCurFrame() moho:NewKeyframe(CHANNEL_BONE_S) self:UpdateWidgets(moho) end elseif (msg == self.CHANGE_S) then self:ChangeScale(moho) elseif (msg == self.RESET_R) then if (moho:CountSelectedBones(true) > 0) then moho.document:PrepUndo(moho.layer, true) moho.document:SetDirty() for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if (bone.fSelected) then bone.fAnimAngle:SetValue(moho.layerFrame, bone.fAnimAngle:GetValue(0)) end end moho.layer:UpdateCurFrame() moho:NewKeyframe(CHANNEL_BONE) self:UpdateWidgets(moho) end elseif (msg == self.CHANGE_R) then self:ChangeAngle(moho) elseif (msg == self.SHOW_PATHS) then self.showPath = self.pathCheck:Value() moho:UpdateUI() elseif (msg == self.SHOW_LABELS) then self.showLabel = self.labelCheck:Value() moho:UpdateUI() elseif (msg == self.SMARTONLYCHECK) then self.smartOnly = self.smartonlyCheck:Value() moho:UpdateUI() elseif (msg == self.FLIP_H) then self:FlipBones(moho, skel, true) elseif (msg == self.FLIP_V) then self:FlipBones(moho, skel, false) elseif (msg >= self.SELECTITEM) then for i = 0, skel:CountBones() - 1 do skel:Bone(i).fSelected = (i == msg - self.SELECTITEM) end moho:UpdateUI() elseif (msg == self.SETTINGSBUTTON) then self.dlog.document = moho.document self.dlog.layer = moho.layer self.dlog.layerFrame = moho.layerFrame self.dlog.skel = skel if (skel:SelectedBoneID() >= 0) then self.dlog.bone = skel:Bone(skel:SelectedBoneID()) else self.dlog.bone = nil end elseif (msg == self.NONEBONE) then self.nonBone = self.nonBoneCheck:Value() elseif (msg == self.INDMODE) then self.indMode = self.indModeCheck:Value() end end function AE_TransformBone:IsASmartBone(moho, skel, bone) local name = bone:Name() if not moho.layer:HasAction(name) then return false end if string.find(name, "|") then return false end local boneID = skel:BoneID(bone) for i, layer in AE_Utilities:IterateAllLayers(moho) do if layer:ControllingSkeleton() == skel then local parentBone = layer:LayerParentBone() if parentBone >= 0 then if parentBone == boneID then return false end else local meshLayer = moho:LayerAsVector(layer) if meshLayer then local mesh = meshLayer:Mesh() for p=0, mesh:CountPoints()-1 do if mesh:Point(p).fParent == boneID then return false end end end end end end return true end function AE_TransformBone:ChangePosX(moho, increment) local pos = self.textX:FloatValue() if increment == 1 then pos = self.textX:FloatValue() + self.posIncr elseif increment == -1 then pos = self.textX:FloatValue() - self.posIncr end local skel = moho:Skeleton() if (moho:CountSelectedBones(true) > 0) then moho.document:PrepUndo(moho.layer, true) moho.document:SetDirty() for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if (bone.fSelected) then bone.fPos.x = pos bone.fAnimPos:SetValue(moho.layerFrame, bone.fPos) end end moho.layer:UpdateCurFrame() moho:NewKeyframe(CHANNEL_BONE_T) end self.textX:SetValue(pos) end function AE_TransformBone:ChangePosY(moho, increment) local pos = self.textY:FloatValue() if increment == 1 then pos = self.textY:FloatValue() + self.posIncr elseif increment == -1 then pos = self.textY:FloatValue() - self.posIncr end local skel = moho:Skeleton() if (moho:CountSelectedBones(true) > 0) then moho.document:PrepUndo(moho.layer, true) moho.document:SetDirty() for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if (bone.fSelected) then bone.fPos.y = pos bone.fAnimPos:SetValue(moho.layerFrame, bone.fPos) end end moho.layer:UpdateCurFrame() moho:NewKeyframe(CHANNEL_BONE_T) end self.textY:SetValue(pos) end function AE_TransformBone:ChangeScale(moho, increment) local scale = self.scale:FloatValue() if increment == 1 then scale = self.scale:FloatValue() + self.scaleIncr elseif increment == -1 then scale = self.scale:FloatValue() - self.scaleIncr end local skel = moho:Skeleton() if (moho:CountSelectedBones(true) > 0) then moho.document:PrepUndo(moho.layer, true) moho.document:SetDirty() for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if (bone.fSelected) then bone.fScale = scale bone.fAnimScale:SetValue(moho.layerFrame, bone.fScale) end end moho.layer:UpdateCurFrame() moho:NewKeyframe(CHANNEL_BONE_S) end self.scale:SetValue(scale) end function AE_TransformBone:ChangeAngle(moho, increment) local angle = self.angle:FloatValue() if increment == 1 then angle = self.angle:FloatValue() + self.angleIncr elseif increment == -1 then angle = self.angle:FloatValue() - self.angleIncr end local skel = moho:Skeleton() if (moho:CountSelectedBones(true) > 0) then moho.document:PrepUndo(moho.layer, true) moho.document:SetDirty() for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if (bone.fSelected) then bone.fAngle = math.rad(angle) bone.fAnimAngle:SetValue(moho.layerFrame, bone.fAngle) end end moho.layer:UpdateCurFrame() moho:NewKeyframe(CHANNEL_BONE) end self.angle:SetValue(angle) end function AE_TransformBone:KeyIncrements(moho, keyEvent) if keyEvent.keyCode == LM.GUI.KEY_UP and keyEvent.shiftKey and keyEvent.ctrlKey then self:ChangePosY(moho, 1) return true elseif keyEvent.keyCode == LM.GUI.KEY_DOWN and keyEvent.shiftKey and keyEvent.ctrlKey then self:ChangePosY(moho, -1) return true elseif keyEvent.keyCode == LM.GUI.KEY_LEFT and keyEvent.shiftKey and keyEvent.ctrlKey then self:ChangePosX(moho, -1) return true elseif keyEvent.keyCode == LM.GUI.KEY_RIGHT and keyEvent.shiftKey and keyEvent.ctrlKey then self:ChangePosX(moho, 1) return true elseif keyEvent.keyCode == LM.GUI.KEY_LEFT and keyEvent.ctrlKey then self:ChangeAngle(moho, 1) return true elseif keyEvent.keyCode == LM.GUI.KEY_RIGHT and keyEvent.ctrlKey then self:ChangeAngle(moho, -1) return true elseif keyEvent.keyCode == LM.GUI.KEY_UP and keyEvent.ctrlKey then self:ChangeScale(moho, 1) return true elseif keyEvent.keyCode == LM.GUI.KEY_DOWN and keyEvent.ctrlKey then self:ChangeScale(moho, -1) return true else return false end end function AE_TransformBone:StoreChildTransforms(moho) self.storedChildTransforms = {} if moho:CountSelectedBones() ~= 1 then return end --TODO: get time segment for active bone local skel = moho:Skeleton() local activeBone = skel:Bone(skel:SelectedBoneID()) local testChannel = activeBone.fAnimScale if (self.mode == 0) then testChannel = activeBone.fAnimPos elseif (self.mode == 1) then testChannel = activeBone.fAnimAngle end --get time segment where bone values changes local startKeyID = testChannel:GetClosestKeyID(moho.layerFrame) local startFrame = testChannel:GetKeyWhen(startKeyID) if startFrame == moho.layerFrame then startKeyID = startKeyID - 1 startFrame = testChannel:GetKeyWhen(startKeyID) end if startFrame == 0 then startFrame = 1 end local endKeyID = startKeyID + 1 local endFrame = 0 if endKeyID < testChannel:CountKeys() then endFrame = testChannel:GetKeyWhen(endKeyID) if endFrame == moho.layerFrame then endKeyID = endKeyID + 1 if endKeyID < testChannel:CountKeys() then endFrame = testChannel:GetKeyWhen(endKeyID) else endFrame = 0 end end end --startFrame = startFrame - moho.layer:TotalTimingOffset() --if endFrame ~= 0 then endFrame = endFrame - moho.layer:TotalTimingOffset() for i, layer in AE_Utilities:IterateAllLayers(moho) do if layer:ControllingSkeleton() == skel then local localStart = startFrame -- + layer.TotalTimingOffset() local localEnd = endFrame -- + layer.TotalTimingOffset() local curFrame = moho.frame -- + layer.TotalTimingOffset local layerParentBone = layer:LayerParentBone() if layerParentBone == skel:SelectedBoneID() or (layerParentBone > -1 and skel:IsAncestorSelected(layerParentBone)) then --TODO: get dependent layers elseif layerParentBone == -1 and layer:LayerType() == MOHO.LT_VECTOR then --get dependent points for active bone local mesh = moho:LayerAsVector(layer):Mesh() for p = 0, mesh:CountPoints()-1 do local point = mesh:Point(p) if point.fParent == skel:SelectedBoneID() or (point.fParent > -1 and skel:IsAncestorSelected(point.fParent)) then if endFrame == 0 then localEnd = point.fAnimPos:Duration() end --store global point position for current frame local curFrameObj = {["frame"] = curFrame, ["type"] = "point", ["layer"] = layer, ["point"] = point } curFrameObj.pos = AE_Utilities:GetPointBoneTransformedPos(moho, layer, point, curFrame) local fPosContainer = LM.Vector2:new_local() fPosContainer:Set(point.fPos) curFrameObj.fPos = fPosContainer curFrameObj.channelPos = point.fAnimPos:GetValue(curFrame) table.insert(self.storedChildTransforms, curFrameObj) --store global point position for every key in segment for f = localStart, localEnd do if f ~= curFrame and point.fAnimPos:HasKey(f) then nextFrameObj = {["frame"] = f, ["type"] = "point", ["layer"] = layer, ["point"] = point } nextFrameObj.pos = AE_Utilities:GetPointBoneTransformedPos(moho, layer, point, f) table.insert(self.storedChildTransforms, nextFrameObj) end end end end end end end --TODO: get dependent bones end function AE_TransformBone:RestoreChildTransforms(moho, curFrameOnly) --print("Restoring child transforms from array of ", #self.storedChildTransforms) for k, v in pairs(self.storedChildTransforms) do --print(k, " frame ", v.frame) if (not curFrameOnly) or (v.frame == moho.layerFrame) then --print(tostring(v.point), " to ", v.pos.x, " ", v.pos.y, " at ", v.frame) if v.type == "point" then if v.fPos then local dif = v.point.fPos - v.fPos local channelPos = v.point.fAnimPos:GetValue(v.frame) v.point.fAnimPos:SetValue(v.frame, channelPos - dif) else local curPos = AE_Utilities:GetPointBoneTransformedPos(moho, v.layer, v.point, v.frame) local dif = v.pos - curPos local channelPos = v.point.fAnimPos:GetValue(v.frame) v.point.fAnimPos:SetValue(v.frame, channelPos + dif) v.layer:UpdateCurFrame() end --else if v.type == end end end if not curFrameOnly then self.storedChildTransforms = {} end end
Modified transform bone tool
Listed
Author: A.Evseeva
View Script
Script type: Tool
Uploaded: Apr 30 2021, 06:19
Last modified: May 20 2022, 13:41
Script Version: 6.44
Labels, paths, custom step and so on
Added features:
* display bone names on mouse move even in "Show Curves" mode off (thanks to Heyvern vector font)
* display true paths for any bone, independent or parented, inside active area
* filter select bone menu with smartbones only
* customizable step for shift+mouse bone rotation, and other hotkey steps
* use "Relative keyframes" timeline mode to translate (or rotate) group of independent bones over multiply keys by same distance
* new "Transform independently" mode lets transform bone in any frame or action without transforming its dependent vertices
* + and = keys select all direct children of selected bone; With shift modifier -- select all the tree of children.
* key DELETE also deletes selected bones' smart actionsÂ
* fixed rotation of multiple independent-angled bones
* when rotate muliple selected bones origin is set to nearest picked bone's origin
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: 2030
Modified transform bone tool
Listed
Author: A.Evseeva
View Script
Script type: Tool
Uploaded: Apr 30 2021, 06:19
Last modified: May 20 2022, 13:41
Script Version: 6.44
Labels, paths, custom step and so on
Added features:
* display bone names on mouse move even in "Show Curves" mode off (thanks to Heyvern vector font)
* display true paths for any bone, independent or parented, inside active area
* filter select bone menu with smartbones only
* customizable step for shift+mouse bone rotation, and other hotkey steps
* use "Relative keyframes" timeline mode to translate (or rotate) group of independent bones over multiply keys by same distance
* new "Transform independently" mode lets transform bone in any frame or action without transforming its dependent vertices
* + and = keys select all direct children of selected bone; With shift modifier -- select all the tree of children.
* key DELETE also deletes selected bones' smart actionsÂ
* fixed rotation of multiple independent-angled bones
* when rotate muliple selected bones origin is set to nearest picked bone's origin
* display bone names on mouse move even in "Show Curves" mode off (thanks to Heyvern vector font)
* display true paths for any bone, independent or parented, inside active area
* filter select bone menu with smartbones only
* customizable step for shift+mouse bone rotation, and other hotkey steps
* use "Relative keyframes" timeline mode to translate (or rotate) group of independent bones over multiply keys by same distance
* new "Transform independently" mode lets transform bone in any frame or action without transforming its dependent vertices
* + and = keys select all direct children of selected bone; With shift modifier -- select all the tree of children.
* key DELETE also deletes selected bones' smart actionsÂ
* fixed rotation of multiple independent-angled bones
* when rotate muliple selected bones origin is set to nearest picked bone's origin
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: 2030