-- ************************************************** -- Provide Moho with the name of this script object -- ************************************************** ScriptName = "MR_CurveTool" -- ************************************************** -- General information about this script -- ************************************************** MR_CurveTool = {} function MR_CurveTool:Name() return self:Localize('UILabel') end function MR_CurveTool:Version() return '4.1.3' end function MR_CurveTool:UILabel() return self:Localize('UILabel') end function MR_CurveTool:Creator() return 'Eugene Babich, Alexandra Evseeva, Dauid' end function MR_CurveTool:Description() return self:Localize('Description') end -- ************************************************** -- Is Relevant / Is Enabled -- ************************************************** function MR_CurveTool:IsRelevant(moho) local mesh = moho:DrawingMesh() if (mesh == nil) then return false end local v1, v2, v3 = MR_Utilities:GetMohoVersion(moho) self.mohoVersion = v1 self.isMoho13_5_3 = true if not v3 then v3 = 0 end if v1 < 13 then self.isMoho13_5_3 = false elseif v1 == 13 then if v2 < 5 then self.isMoho13_5_3 = false elseif v3 < 3 then self.isMoho13_5_3 = false end end self.selectedPointID = -1 self.startCurvePointID = -1 self.drawingStatus = false self.drawWeldPoint = false self.startPoint = 1000000 self.step = 0 return true end function MR_CurveTool:IsEnabled(moho) local mesh = moho:DrawingMesh() if (mesh == nil) then return false end local v1, v2, v3 = MR_Utilities:GetMohoVersion(moho) self.mohoVersion = v1 self.isMoho13_5_2 = true if not v3 then v3 = 0 end if v1 < 13 then self.isMoho13_5_2 = false elseif v2 < 5 then self.isMoho13_5_2 = false elseif v3 < 3 then self.isMoho13_5_2 = false end if self.isMoho13_5_2 then if (mesh:ContinuousTriangulation()) then return false end end self.selectedPoints = moho:CountSelectedPoints() if moho:CurrentTool() ~= 'MR_CurveTool' then self.selectedPointID = -1 self.startCurvePointID = -1 self.drawingStatus = false self.drawWeldPoint = false self.startPoint = 1000000 self.step = 0 end return true end -- ************************************************** -- Recurring Values -- ************************************************** MR_CurveTool.drawInZeroFrame = true MR_CurveTool.drawInNonZeroFrame = true MR_CurveTool.alwaysDrawOnFBF = true MR_CurveTool.showAllHandles = false MR_CurveTool.enableSkewTransformation = true MR_CurveTool.enableDistortTransformation = true MR_CurveTool.clickToSelect = true MR_CurveTool.drawBehind = false MR_CurveTool.usePeakForCorners = false MR_CurveTool.curvatureSC = 0.33 MR_CurveTool.points = 1 MR_CurveTool.step = 0 MR_CurveTool.singleCurveMode = false MR_CurveTool.drawingStatus = false MR_CurveTool.showHandles = true MR_CurveTool.fixedHandles = true MR_CurveTool.useBezierHandles = true MR_CurveTool.threshold = 0.05 MR_CurveTool.autoWeld = true MR_CurveTool.autoWeldRadius = 144 MR_CurveTool.sharpCorners = false MR_CurveTool.autoFill = true MR_CurveTool.autoStroke = true MR_CurveTool.selectedPointID = -1 MR_CurveTool.curvePointID = -1 MR_CurveTool.lastSelectedPointID = -1 MR_CurveTool.curvature = 0.33 MR_CurveTool.lastClickVec = LM.Vector2:new_local() MR_CurveTool.closest = 100000 MR_CurveTool.closestID = -1 MR_CurveTool.endWeldVec = LM.Vector2:new_local() MR_CurveTool.endWeldVec:Set(-10000000, -10000000) MR_CurveTool.endWeldToPoint = true MR_CurveTool.drawWeldPoint = false MR_CurveTool.startPoint = -1 MR_CurveTool.startPointClick = false MR_CurveTool.isBackspace = false MR_CurveTool.needCreateNewPoint = false MR_CurveTool.isMousePressed = false MR_CurveTool.lastPointID = -1 MR_CurveTool.isBezierChanged = false MR_CurveTool.applyPeakedCorner = false MR_CurveTool.isLastPointBezierMode = false MR_CurveTool.isStartPoint = false MR_CurveTool.continueEndPoint = false MR_CurveTool.handlePt = LM.Vector2:new_local() MR_CurveTool.handlePt2 = LM.Vector2:new_local() MR_CurveTool.midPt = LM.Vector2:new_local() MR_CurveTool.startCurvePointID = -1 MR_CurveTool.targetPointID = -1 MR_CurveTool.statusMode = 0 -- 1 close curve MR_CurveTool.peakedCornerDef = 0.0001 MR_CurveTool.peakedCorner = 0.0001 MR_CurveTool.needCreateShape = false MR_CurveTool.curveForCreateShape = nil MR_CurveTool.curveIDForMove = 0 MR_CurveTool.fillColorR = 255 MR_CurveTool.fillColorG = 255 MR_CurveTool.fillColorB = 255 MR_CurveTool.fillColorA = 255 MR_CurveTool.strokeColorR = 0 MR_CurveTool.strokeColorG = 0 MR_CurveTool.strokeColorB = 0 MR_CurveTool.strokeColorA = 255 MR_CurveTool.strokeWidth = 1 MR_CurveTool.isMouseDragging = false MR_CurveTool.selRect = LM.Rect:new_local() MR_CurveTool.movePoints = true MR_CurveTool.dragPoint = false MR_CurveTool.prewVec = LM.Vector2:new_local() MR_CurveTool.prewVec:Set(-10000, -10000) MR_CurveTool.isFirstClick = false MR_CurveTool.isCurveEnded = false MR_CurveTool.selectedPoints = 0 MR_CurveTool.lastVec = LM.Vector2:new_local() MR_CurveTool.pivotOffset = LM.Vector2:new_local() MR_CurveTool.centerVec = LM.Vector2:new_local() MR_CurveTool.markerR = 8 MR_CurveTool.dragging = false MR_CurveTool.createdMidPoint = false MR_CurveTool.pointPoseChanged = false MR_CurveTool.isFBF = false MR_CurveTool.clickOffset = LM.Vector2:new_local() MR_CurveTool.clickPos = LM.Vector2:new_local() MR_CurveTool.mohoVersion = 0 MR_CurveTool.reset = false -- ************************************************** -- Prefs -- ************************************************** function MR_CurveTool:LoadPrefs(prefs) self.drawInZeroFrame = prefs:GetBool("MR_CurveTool.drawInZeroFrame", true) self.drawInNonZeroFrame = prefs:GetBool("MR_CurveTool.drawInNonZeroFrame", true) self.alwaysDrawOnFBF = prefs:GetBool("MR_CurveTool.alwaysDrawOnFBF", true) self.showAllHandles = prefs:GetBool("MR_CurveTool.showAllHandles", false) self.enableSkewTransformation = prefs:GetBool("MR_CurveTool.enableSkewTransformation", true) self.enableDistortTransformation = prefs:GetBool("MR_CurveTool.enableDistortTransformation", true) self.clickToSelect = prefs:GetBool("MR_CurveTool.clickToSelect", true) self.drawBehind = prefs:GetBool("MR_CurveTool.drawBehind", false) self.usePeakForCorners = prefs:GetBool("MR_CurveTool.usePeakForCorners", false) self.curvatureSC = prefs:GetFloat("MR_CurveTool.curvatureSC", 0.33) self.points = prefs:GetInt("MR_CurveTool.points", 1) self.singleCurveMode = prefs:GetBool("MR_CurveTool.singleCurveMode", false) self.curvature = prefs:GetFloat("MR_CurveTool.curvature", 0.33) self.showHandles = prefs:GetBool("MR_CurveTool.showHandles", true) self.fixedHandles = prefs:GetBool("MR_CurveTool.fixedHandles", true) self.useBezierHandles = prefs:GetBool("MR_CurveTool.useBezierHandles", true) self.threshold = prefs:GetFloat("MR_CurveTool.threshold", 0.05) self.autoWeld = prefs:GetBool("MR_CurveTool.autoWeld", true) self.sharpCorners = prefs:GetBool("MR_CurveTool.sharpCorners", false) self.autoFill = prefs:GetBool("MR_CurveTool.autoFill", true) self.autoStroke = prefs:GetBool("MR_CurveTool.autoStroke", true) self.fillColorR = prefs:GetInt("MR_CurveTool.fillColorR", 255) self.fillColorG = prefs:GetInt("MR_CurveTool.fillColorG", 255) self.fillColorB = prefs:GetInt("MR_CurveTool.fillColorB", 255) self.fillColorA = prefs:GetInt("MR_CurveTool.fillColorA", 255) self.strokeColorR = prefs:GetInt("MR_CurveTool.strokeColorR", 0) self.strokeColorG = prefs:GetInt("MR_CurveTool.strokeColorG", 0) self.strokeColorB = prefs:GetInt("MR_CurveTool.strokeColorB", 0) self.strokeColorA = prefs:GetInt("MR_CurveTool.strokeColorA", 255) self.strokeWidth = prefs:GetFloat("MR_CurveTool.strokeWidth", 1) end function MR_CurveTool:SavePrefs(prefs) prefs:SetBool("MR_CurveTool.drawInZeroFrame", self.drawInZeroFrame) prefs:SetBool("MR_CurveTool.drawInNonZeroFrame", self.drawInNonZeroFrame) prefs:SetBool("MR_CurveTool.alwaysDrawOnFBF", self.alwaysDrawOnFBF) prefs:SetBool("MR_CurveTool.showAllHandles", self.showAllHandles) prefs:SetBool("MR_CurveTool.enableSkewTransformation", self.enableSkewTransformation) prefs:SetBool("MR_CurveTool.enableDistortTransformation", self.enableDistortTransformation) prefs:SetBool("MR_CurveTool.clickToSelect", self.clickToSelect) prefs:SetBool("MR_CurveTool.drawBehind", self.drawBehind) prefs:SetBool("MR_CurveTool.usePeakForCorners", self.usePeakForCorners) prefs:SetFloat("MR_CurveTool.curvatureSC", self.curvatureSC) prefs:SetInt("MR_CurveTool.points", self.points) prefs:SetBool("MR_CurveTool.singleCurveMode", self.singleCurveMode) prefs:SetFloat("MR_CurveTool.curvature", self.curvature) prefs:SetBool("MR_CurveTool.showHandles", self.showHandles) prefs:SetBool("MR_CurveTool.fixedHandles", self.fixedHandles) prefs:SetBool("MR_CurveTool.useBezierHandles", self.useBezierHandles) prefs:SetFloat("MR_CurveTool.threshold", self.threshold) prefs:SetBool("MR_CurveTool.autoWeld", self.autoWeld) prefs:SetBool("MR_CurveTool.sharpCorners", self.sharpCorners) prefs:SetBool("MR_CurveTool.autoFill", self.autoFill) prefs:SetBool("MR_CurveTool.autoStroke", self.autoStroke) prefs:SetInt("MR_CurveTool.fillColorR", self.fillColorR) prefs:SetInt("MR_CurveTool.fillColorG", self.fillColorG) prefs:SetInt("MR_CurveTool.fillColorB", self.fillColorB) prefs:SetInt("MR_CurveTool.fillColorA", self.fillColorA) prefs:SetInt("MR_CurveTool.strokeColorR", self.strokeColorR) prefs:SetInt("MR_CurveTool.strokeColorG", self.strokeColorG) prefs:SetInt("MR_CurveTool.strokeColorB", self.strokeColorB) prefs:SetInt("MR_CurveTool.strokeColorA", self.strokeColorA) prefs:SetFloat("MR_CurveTool.strokeWidth", self.strokeWidth) end function MR_CurveTool:ResetPrefs() self.drawInZeroFrame = true self.drawInNonZeroFrame = true self.alwaysDrawOnFBF = true self.showAllHandles = false self.enableSkewTransformation = true self.enableDistortTransformation = true self.clickToSelect = true self.drawBehind = false self.usePeakForCorners = false self.curvatureSC = 0.33 self.points = 1 self.singleCurveMode = false self.curvature = 0.33 self.showHandles = true self.fixedHandles = true self.useBezierHandles = true self.threshold = 0.05 self.autoWeld = true self.sharpCorners = false self.autoFill = true self.autoStroke = true self.fillColorR = 255 self.fillColorG = 255 self.fillColorB = 255 self.fillColorA = 255 self.strokeColorR = 0 self.strokeColorG = 0 self.strokeColorB = 0 self.strokeColorA = 255 self.strokeWidth = 1 self.reset = true end -- ************************************************** -- Keyboard/Mouse Control -- ************************************************** function MR_CurveTool:NonDragMouseMove() return true end function MR_CurveTool:OnMouseDown(moho, mouseEvent) local mesh = moho:DrawingMesh() if (mesh == nil) then return end if self.isBezierChanged and self.isMousePressed then self:CloseCurve(moho) self.isMousePressed = false self.isBezierChanged = false return end if self.usePeakForCorners then self.peakedCorner = 0 else self.peakedCorner = self.peakedCornerDef end local doubleClick = mouseEvent.doubleClick self.isFBF = false if moho.layer:LayerType() == MOHO.LT_SWITCH then if moho:LayerAsSwitch(moho.layer):IsFBFLayer() then self.isFBF = true end end local closestID = -1 local closest = 1e6 local selectedPoint self.doNotAddNewPoint = false local clickVec = LM.Vector2:new_local() clickVec:Set(mouseEvent.drawingVec) local testVec1 = LM.Vector2:new_local() testVec1:Set(mouseEvent.drawingVec) closestID = mesh:ClosestPoint(testVec1) if closestID >= 0 then local testVec2 = LM.Vector2:new_local() testVec2:Set(mesh:Point(closestID).fPos) closest = self:GetColosestVec(moho, mouseEvent.view, testVec1,testVec2) end self.selectedPoints = moho:CountSelectedPoints() self.isMouseDragging = false if ((mouseEvent.shiftKey and mouseEvent.altKey) or (mouseEvent.ctrlKey and mouseEvent.altKey) or (mouseEvent.shiftKey and mouseEvent.ctrlKey) and not self.drawingStatus) or (self.selectedPoints > 1 and mouseEvent.altKey and mouseEvent.ctrlKey and not mouseEvent.shiftKey) or (not self.drawInZeroFrame and moho.frame == 0 and self.selectedPoints == 0) then self.isMouseDragging = true if not ((mouseEvent.shiftKey and mouseEvent.ctrlKey) or (not mouseEvent.shiftKey and mouseEvent.altKey and mouseEvent.ctrlKey) or ((self.selectedPoints > 1 and mouseEvent.altKey and mouseEvent.ctrlKey and not mouseEvent.shiftKey))) then mesh:SelectNone() end self.selRect.left = mouseEvent.startPt.x self.selRect.top = mouseEvent.startPt.y self.selRect.right = mouseEvent.pt.x self.selRect.bottom = mouseEvent.pt.y mouseEvent.view:Graphics():SelectionRect(self.selRect) mouseEvent.view:DrawMe() return else local isDrawingEnabled = true if not self.drawInZeroFrame and moho.frame == 0 or not self.drawInNonZeroFrame and moho.frame ~= 0 then isDrawingEnabled = false end if self.isFBF and self.alwaysDrawOnFBF then isDrawingEnabled = true end if not isDrawingEnabled then self.handleSide = 0 if self.selectedPoints == 1 then self:TestForClosestHandle(moho, mouseEvent) end if not (not self.drawingStatus and closestID >= 0 and closest < self.autoWeldRadius * 1.5) and self.selectedPoints <= 1 and self.handleSide == 0 then self.isMouseDragging = true self.selRect.left = mouseEvent.startPt.x self.selRect.top = mouseEvent.startPt.y self.selRect.right = mouseEvent.pt.x self.selRect.bottom = mouseEvent.pt.y mouseEvent.view:Graphics():SelectionRect(self.selRect) mouseEvent.view:DrawMe() return end end end if moho.layerFrame > 0 then self:ClearPointKeys(moho, self.selectedPointID) self:ClearPointKeys(moho, self.lastSelectedPointID) end if not (self.step == 1 or self.step == 2) then moho.document:PrepUndo(moho.drawingLayer) moho.document:SetDirty() end mesh:PrepMovePoints() local totalPoints = mesh:CountPoints() if self.fixedHandles then mesh:PrepFixedHandles(moho.layerFrame) self:FixHandles(moho, mesh) end if self.drawingStatus and self.selectedPoints == 1 then if self.selectedPointID >= 0 and self.selectedPointID < totalPoints then local point = mesh:Point(self.selectedPointID) point.fSelected = true end end self.curveID = -1 self.curveIDForMove = -1 self.selectedCurvePointID = -1 self.curvePointID = -1 self.needCreateNewPoint = false self.lastPointID = -1 self.isBezierChanged = false self.applyPeakedCorner = false self.isStartPoint = false self.continueEndPoint = false self.startCurvePointID = -1 self.targetPointID = -1 self.statusMode = 0 self.needCreateShape = false self.dragPoint = false self.curveForCreateShape = nil self.isFirstClick = false self.isCurveEnded = false self.createdMidPoint = false self.prewVec:Set(mouseEvent.drawingVec) self.handleSide = 0 self.clickOffset:Set(0, 0) self.pointPoseChanged = false self.transformation = false self.outside = false local clickToSelect = self.clickToSelect if not self.drawInNonZeroFrame and moho.frame ~= 0 and not self.isFBF then clickToSelect = true end if (clickToSelect and not doubleClick and not self.drawingStatus and closestID >= 0 and closest < self.autoWeldRadius * 1.5 and self.selectedPoints == 0 ) then if closestID >= 0 then mesh:Point(closestID).fSelected = true self.selectedPoints = 1 self.drawingStatus = false self.drawWeldPoint = false self.selectedPointID = -1 self.startPoint = -1 self.curveID = -1 self.curveIDForMove = -1 self.selectedCurvePointID = -1 self.curvePointID = -1 self.needCreateNewPoint = false self.lastPointID = -1 self.isBezierChanged = false self.applyPeakedCorner = false self.isStartPoint = false self.continueEndPoint = false self.startCurvePointID = -1 self.targetPointID = -1 self.statusMode = 0 self.needCreateShape = false self.dragPoint = false self.curveForCreateShape = nil self.isFirstClick = false self.isCurveEnded = false self.createdMidPoint = false self.prewVec:Set(mouseEvent.drawingVec) self.handleSide = 0 self.clickOffset:Set(0, 0) self.pointPoseChanged = false end end if (clickToSelect and not doubleClick and not self.drawingStatus) or not clickToSelect then if self.selectedPoints == 1 and not self.drawingStatus then self:TestForClosestHandle(moho, mouseEvent) self:DrawMe(moho, mouseEvent.view) if self.handleSide ~= 0 then self.dragPoint = true self.drawingStatus = true self.savedVal = 0 self.selectedPointID = self.selID local pt = mesh:Point(self.selectedPointID) local handlePt = self.startHandle + (mouseEvent.vec - mouseEvent.startVec) if (moho.gridOn) then moho:SnapToGrid(handlePt) end local curve = mesh:Curve(self.handleCurveID) local oldWeight = curve:GetWeight(self.handlePointID, moho.layerFrame, (self.handleSide == -1)) local newVector = handlePt - self.startFPos local weightMultiply = newVector:Mag()/self.startVectorMag local newWeight = newVector:Mag()/self.weightMultiplier - self.weightDelta self.weightStartDelta = newWeight - oldWeight self.flipDirection = self:CheckFlipDirection(moho, pt) moho.drawingLayer:UpdateCurFrame() return else if closest < self.autoWeldRadius * 1.5 then local point local pointID for i=0, mesh:CountPoints()-1 do point = mesh:Point(i) if point.fSelected then pointID = i break end end if closestID == pointID then mesh:PrepFixedHandles(moho.layerFrame) self.selectedPointID = pointID point.fTempPos:Set(point.fPos) self.clickOffset:Set(point.fPos - mouseEvent.drawingVec) self.dragPoint = true self.doNotAddNewPoint = true self.drawingStatus = true self.drawWeldPoint = false mesh:PrepMovePoints() if self.fixedHandles then mesh:PrepFixedHandles(moho.layerFrame) self:FixHandles(moho, mesh) self:MakeFlipDirectionList(moho) end moho.drawingLayer:UpdateCurFrame() self:PopulateSelList(moho, mesh) mouseEvent.view:DrawMe() return else mesh:SelectNone() return end else mesh:SelectNone() return end end elseif self.selectedPoints > 1 then self.dragging = true self.endWeldVec:Set(-10000000, -10000000) self.centerVec = mesh:SelectedCenter() self.centerVec = self.centerVec + self.pivotOffset self.startPivotOffset = LM.Vector2:new_local() self.startPivotOffset:Set(self.pivotOffset) self.mode, self.outside = self:TestMousePoint(moho, mouseEvent) self.selectedMin = LM.Vector2:new_local() self.selectedMax = LM.Vector2:new_local() mesh:SelectedBounds(self.selectedMin, self.selectedMax) moho.document:SetDirty() self.numSel = self.selectedPoints if doubleClick and self.mode ~= 11 then -- pivot point mesh:SelectNone() self.dragging = false return end if (self.mode == 0) then -- translate elseif (self.mode == 1) then -- rotate self.startAngle = 0 self.lastVec:Set(mouseEvent.drawingVec) elseif (self.mode == 11) then -- pivot point if mouseEvent.doubleClick then self.centerVec:Set(mesh:SelectedCenter()) self.pivotOffset:Set(0, 0) end elseif (self.mode >= 24 and self.mode <= 27) then -- distord self.handle = 'none' self.bottomLeft = LM.Vector2:new_local() self.topLeft = LM.Vector2:new_local() self.bottomRight = LM.Vector2:new_local() self.topRight = LM.Vector2:new_local() self.horizonPercent = {} self.vertPercent = {} self.ptlist = {} self.minVec = LM.Vector2:new_local() self.maxVec = LM.Vector2:new_local() mesh:SelectedBounds(self.minVec, self.maxVec) self.clickPos:Set(mouseEvent.drawingStartVec) self.bottomLeft.x = self.minVec.x self.bottomLeft.y = self.minVec.y self.topLeft.x = self.minVec.x self.topLeft.y = self.maxVec.y self.bottomRight.x = self.maxVec.x self.bottomRight.y = self.minVec.y self.topRight.x = self.maxVec.x self.topRight.y = self.maxVec.y for i = 0, mesh:CountPoints() - 1 do local pt = mesh:Point(i) if pt.fSelected then self.ptlist[i + 1] = pt local maxXdistance = self.topRight.x - self.topLeft.x local Xdistance = pt.fPos.x - self.topLeft.x self.horizonPercent[i + 1] = Xdistance/maxXdistance local maxYdistance = self.bottomLeft.y - self.topLeft.y local Ydistance = pt.fPos.y - self.topLeft.y self.vertPercent[i + 1] = Ydistance/maxYdistance end end local maxXdistance = self.topRight.x - self.topLeft.x local Xdistance = self.centerVec.x - self.topLeft.x self.horizonPercentCenter = Xdistance / maxXdistance local maxYdistance = self.bottomLeft.y - self.topLeft.y local Ydistance = self.centerVec.y - self.topLeft.y self.vertPercentCenter = Ydistance / maxYdistance elseif (self.mode >= 20 and self.mode <= 23) then -- skew self.selList = {} for i = 0, mesh:CountPoints() - 1 do local point = mesh:Point(i) if point.fSelected then self.selList[i + 1] = point end end self.minVec = LM.Vector2:new_local() self.maxVec = LM.Vector2:new_local() mesh:SelectedBounds(self.minVec, self.maxVec) elseif (self.mode >= 2 and self.mode <= 9) then -- scale self.lastScaleX = 1.0 self.lastScaleY = 1.0 self.minVec = LM.Vector2:new_local() self.maxVec = LM.Vector2:new_local() mesh:SelectedBounds(self.minVec, self.maxVec) end if self.fixedHandles then self:MakeFlipDirectionList(moho) mesh:PrepFixedHandles(moho.layerFrame) end mesh:PrepMovePoints() self:PopulateSelList(moho, mesh) self:AddPointKeyframe(moho, moho.layerFrame, moho.drawingLayer) mouseEvent.view:DrawMe() return end end if doubleClick and self.selectedPoints > 1 then self.mode = self:TestMousePoint(moho, mouseEvent) if (self.mode == 11) then -- pivot point if mouseEvent.doubleClick then self.centerVec:Set(mesh:SelectedCenter()) self.pivotOffset:Set(0, 0) return end else mesh:SelectNone() self.dragging = false return end end if not self.drawInZeroFrame and moho.frame == 0 and not (self.isFBF and self.alwaysDrawOnFBF) then return end if not self.drawInNonZeroFrame and moho.frame ~= 0 and not (self.isFBF and self.alwaysDrawOnFBF) then return end if moho.drawingLayer:CurrentAction() ~= "" then return end if self.singleCurveMode then if self.step == 0 then self.isWelded = false self.step = 1 self.drawingStatus = true self.isMousePressed = true elseif self.step == 1 then self.step = 2 end self.selectedPoints = 0 mesh:PrepFixedHandles(moho.layerFrame) mesh:SelectNone() if self.step == 1 then self.isNewCurve = false local closestID = -1 local closest = 1e6 local clickVec = LM.Vector2:new_local() clickVec:Set(mouseEvent.drawingVec) local testVec1 = LM.Vector2:new_local() testVec1:Set(mouseEvent.drawingVec) closestID = mesh:ClosestPoint(testVec1) self.firstPointID = -1 self.secondPointID = -1 if closestID >= 0 then local testVec2 = LM.Vector2:new_local() testVec2:Set(mesh:Point(closestID).fPos) closest = self:GetColosestVec(moho, mouseEvent.view, testVec1,testVec2) end if (not mouseEvent.altKey and self.autoWeld) or (mouseEvent.altKey and not self.autoWeld) then if closest < self.autoWeldRadius and closestID >= 0 then self.firstPointID = closestID else local newPoint = self:AddPointOnCurve(moho, mouseEvent) if newPoint then self.clickOffset:Set(newPoint.fPos - mouseEvent.drawingVec) mesh:SelectNone() self.selectedPointID = mesh:PointID(newPoint) newPoint.fSelected = true newPoint.fTempPos:Set(newPoint.fPos) self.dragPoint = true self.doNotAddNewPoint = true mesh:PrepFixedHandles(moho.layerFrame) self.createdMidPoint = true self.step = 0 self:FixHandles(moho, mesh) self:MakeFlipDirectionList(moho) self:PopulateSelList(moho, mesh) self:ClearPointKeys(moho, mesh:PointID(newPoint)) local curve, ptID = newPoint:Curve(newPoint:CountCurves()-1, -1) if curve.fClosed then if ptID + 1 < curve:CountPoints() then self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID + 1))) else self:ClearPointKeys(moho, mesh:PointID(curve:Point(0))) end if ptID - 1 >= 0 then self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID - 1))) else self:ClearPointKeys(moho, mesh:PointID(curve:Point(curve:CountPoints()-1))) end else if ptID + 1 < curve:CountPoints() then self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID + 1))) end if ptID - 1 >= 0 then self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID - 1))) end end return end end end if self.firstPointID == -1 then local newPoint local newPointID if self.autoWeld then newPoint= self:AddPointOnCurve(moho, mouseEvent) newPointID = mesh:PointID(newPoint) end if newPoint then mesh:AddPoint(clickVec, -1, moho.layerFrame) self.firstPointID = mesh:CountPoints() - 2 mesh:WeldPoints(self.firstPointID, newPointID, moho.layerFrame) mesh:PrepFixedHandles(moho.layerFrame) self.secondPointID = mesh:CountPoints() - 1 self.firstPointID = newPointID else self.isNewCurve = true mesh:AddPoint(clickVec, -1, moho.layerFrame) self.firstPointID = mesh:CountPoints() - 2 self.secondPointID = self.firstPointID + 1 end else local firstPoint = mesh:Point(self.firstPointID) if firstPoint:IsEndpoint() then mesh:AddPoint(clickVec, self.firstPointID, moho.layerFrame) self.secondPointID = mesh:CountPoints() - 1 else mesh:AddPoint(clickVec, -1, moho.layerFrame) self.firstPointID = mesh:CountPoints() - 2 mesh:WeldPoints(self.firstPointID, closestID, moho.layerFrame) mesh:PrepFixedHandles(moho.layerFrame) self.secondPointID = mesh:CountPoints() - 1 self.firstPointID = closestID end end end self.selectedPointID = self.secondPointID return end if clickToSelect and closest < self.autoWeldRadius * 1.5 and closestID >= 0 and doubleClick and not self.drawingStatus then self.selectedPointID = -1 end if self.selectedPointID < 0 then if (not mouseEvent.altKey and self.autoWeld) or (mouseEvent.altKey and not self.autoWeld) then if closest < self.autoWeldRadius then selectedPoint = mesh:Point(closestID) self.selectedPointID = closestID mesh:SelectNone() selectedPoint.fSelected = true self.startPoint = mesh:CountPoints() if selectedPoint:IsEndpoint() then if (mouseEvent.ctrlKey and not self.sharpCorners) or (not mouseEvent.ctrlKey and self.sharpCorners) then selectedPoint:SetCurvature(MOHO.PEAKED + self.peakedCorner, moho.layerFrame) else selectedPoint:SetCurvature(self.curvature, moho.layerFrame) end selectedPoint:ResetControlHandles(moho.layerFrame) self:ClearPointKeys(moho, self.selectedPointID) end if closestID >= 0 then if (clickToSelect and not self.drawingStatus and doubleClick) or not clickToSelect then local testPoint = mesh:Point(closestID) if not testPoint:IsEndpoint() then -- Create new point from mid point local selectedPointPos = LM.Vector2:new_local() selectedPointPos:Set(selectedPoint.fAnimPos:GetValue(moho.layerFrame)) local isEdgePoint = self:IsPointEdge(moho, mesh, mesh:Point(closestID), false) mesh:AddPoint(selectedPointPos, -1, moho.layerFrame) mesh:WeldPoints(mesh:CountPoints() - 1, closestID, moho.layerFrame) selectedPoint.fAnimPos:SetValue(moho.layerFrame, selectedPointPos) self.selectedPointID = mesh:CountPoints() - 1 self.curvePointID = self.selectedPointID self.targetPointID = closestID self.startPoint = self.selectedPointID self.startCurvePointID = closestID self.lastSelectedPointID = self.selectedPointID local firstPoint = mesh:Point(closestID) local point = mesh:Point(self.startPoint) local where = -1 local curve, where = point:Curve(point:CountCurves()-1, where) local curveID = mesh:CurveID(curve) point.fAnimPos:SetValue(moho.layerFrame, selectedPointPos) local screenPt = LM.Point:new_local() self.curveID = curveID self.startHandle = curve:GetControlHandle(self:FindLastCurvePoint(moho, point), moho.layerFrame, false) mouseEvent.view:Graphics():WorldToScreen(self.startHandle, screenPt) local curvePointID = curve:PointID(firstPoint) if curvePointID ~= 0 then curvePointID = self:FindLastCurvePoint(moho, firstPoint) end local handleWeight = curve:GetWeight(curvePointID, moho.layerFrame, false) local handleWeight2 = curve:GetWeight(curvePointID, moho.layerFrame, true) if (curvePointID == 0 and handleWeight == 0) or (curvePointID > 0 and handleWeight2 == 0) or (curvePointID == 0 and handleWeight == 1) or (curvePointID > 0 and handleWeight2 == 1) then curve:ResetControlHandles(curvePointID, moho.layerFrame) curve:SetCurvature(curvePointID, self.curvature, moho.layerFrame) else curve:ResetControlHandles(curvePointID, moho.layerFrame) curve:SetCurvature(curvePointID, self.curvature, moho.layerFrame) end if not isEdgePoint then curve:SetCurvature(curvePointID, MOHO.PEAKED + self.peakedCorner, moho.layerFrame) end if (mouseEvent.ctrlKey and not self.sharpCorners) or (not mouseEvent.ctrlKey and self.sharpCorners)then curve:SetCurvature(curvePointID, MOHO.PEAKED + self.peakedCorner, moho.layerFrame) self.firstPointSharpCorner = true self.applyPeakedCorner = true end mesh:SelectNone() point.fSelected = true mesh:PrepFixedHandles(moho.layerFrame) self.drawingStatus = true self.isMousePressed = true self.isStartPoint = true self.isLastPointBezierMode = false self.isFirstClick = true else self.targetPointID = closestID self.startPointClick = true self.needCreateNewPoint = true mesh:PrepFixedHandles(moho.layerFrame) end end end else local newPoint = self:AddPointOnCurve(moho, mouseEvent) if newPoint then self.clickOffset:Set(newPoint.fPos - mouseEvent.drawingVec) if self.movePoints then mesh:SelectNone() self.selectedPointID = mesh:PointID(newPoint) newPoint.fSelected = true newPoint.fTempPos:Set(newPoint.fPos) self.dragPoint = true self.doNotAddNewPoint = true mesh:PrepFixedHandles(moho.layerFrame) self.createdMidPoint = true self:FixHandles(moho, mesh) self:MakeFlipDirectionList(moho) self:PopulateSelList(moho, mesh) else mesh:SelectNone() self.selectedPointID = - 1 self.doNotAddNewPoint = true self.drawingStatus = false self.drawWeldPoint = false end self:ClearPointKeys(moho, mesh:PointID(newPoint)) local curve, ptID = newPoint:Curve(newPoint:CountCurves()-1, -1) if curve.fClosed then if ptID + 1 < curve:CountPoints() then self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID + 1))) else self:ClearPointKeys(moho, mesh:PointID(curve:Point(0))) end if ptID - 1 >= 0 then self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID - 1))) else self:ClearPointKeys(moho, mesh:PointID(curve:Point(curve:CountPoints()-1))) end else if ptID + 1 < curve:CountPoints() then self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID + 1))) end if ptID - 1 >= 0 then self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID - 1))) end end end end end else mesh:SelectNone() end if self.selectedPointID < 0 then if not self.doNotAddNewPoint then -- create start point mesh:SelectNone() mesh:AddPoint(mouseEvent.drawingVec, -1, moho.layerFrame) self.selectedPointID = mesh:CountPoints() - 1 self.startPoint = self.selectedPointID self.startCurvePointID = mesh:CountPoints() - 2 self.lastSelectedPointID = self.selectedPointID self.lastPointID = self.selectedPointID local firstPoint = mesh:Point(mesh:CountPoints() - 2) local point = mesh:Point(self.startPoint) if (moho.gridOn) then moho:SnapToGrid(firstPoint.fPos) firstPoint.fAnimPos:SetValue(moho.layerFrame, firstPoint.fPos) end point.fTempPos:Set(point.fPos) local curveID = mesh:CountCurves() - 1 local curve = mesh:Curve(curveID) local screenPt = LM.Point:new_local() self.curveID = curveID self.startHandle = curve:GetControlHandle(curve:PointID(point), moho.layerFrame, false) mouseEvent.view:Graphics():WorldToScreen(self.startHandle, screenPt) self.handlePt2:Set(point.fPos) if (mouseEvent.ctrlKey and not self.sharpCorners) or (not mouseEvent.ctrlKey and self.sharpCorners) then firstPoint:SetCurvature(MOHO.PEAKED + self.peakedCorner, moho.layerFrame) firstPoint:ResetControlHandles(moho.layerFrame) self.firstPointSharpCorner = true self.applyPeakedCorner = true else firstPoint:SetCurvature(MOHO.PEAKED + self.peakedCorner, moho.layerFrame) end point:ResetControlHandles(moho.layerFrame) mesh:PrepFixedHandles(moho.layerFrame) self.selectedPointID = mesh:CountPoints() - 1 self.drawingStatus = true self.isMousePressed = true self.isStartPoint = true self.isFirstClick = true end else -- selected point found local testVec1 = LM.Vector2:new_local() testVec1:Set(mouseEvent.drawingVec) local drawingClosestID = mesh:ClosestPoint(testVec1, mesh:CountPoints() - 1) local testVec2 = LM.Vector2:new_local() testVec2:Set(self.lastClickVec) local dis = self:GetColosestVec(moho, mouseEvent.view, testVec1, testVec2) local drawingClosest = self:GetColosestVec(moho, mouseEvent.view, testVec1, mesh:Point(drawingClosestID).fPos) if dis < self.autoWeldRadius * 1.5 and self.drawingStatus and not self.isStartPoint then -- finish stroke self.drawingStatus = false self.drawWeldPoint = false local pointID = mesh:CountPoints() - 1 local point = mesh:Point(pointID) local curve, curvePointId = point:Curve(point:CountCurves()-1, -1) local lastPointCurveID = curvePointId + 2 local fromStart = true if curvePointId ~= 0 then lastPointCurveID = curvePointId - 2 fromStart = false end local lastPointHandlePt = LM.Vector2:new_local() local lastPointHandlePt2 = LM.Vector2:new_local() local needCorrect = false if lastPointCurveID >= 0 and lastPointCurveID < curve:CountPoints() then lastPointHandlePt:Set(curve:GetControlHandle(lastPointCurveID, moho.layerFrame, true)) lastPointHandlePt2:Set(curve:GetControlHandle(lastPointCurveID, moho.layerFrame, false)) needCorrect = true end mesh:DeletePoint(pointID) mesh:SelectNone() local totalPoints = mesh:CountPoints() if totalPoints > 0 then local pt = mesh:Point(totalPoints - 1) pt:SetCurvature(self.curvature, moho.layerFrame) pt:ResetControlHandles(moho.layerFrame) end if needCorrect then if fromStart then lastPointCurveID = lastPointCurveID -1 end curve:SetControlHandle(lastPointCurveID, lastPointHandlePt, moho.layerFrame, true, true) curve:SetControlHandle(lastPointCurveID, lastPointHandlePt2, moho.layerFrame, false, true) end if self.lastSelectedPointID >= 0 and self.lastSelectedPointID < mesh:CountPoints() then local lastPoint = mesh:Point(self.lastSelectedPointID) if lastPoint then local lastCurve, lastCurvePointId = lastPoint:Curve(lastPoint:CountCurves()-1, -1) local prewCurvePointId = lastCurvePointId if lastCurvePointId ~= 0 then prewCurvePointId = prewCurvePointId - 1 else prewCurvePointId = prewCurvePointId + 1 end self:ClearPointKeys(moho, self.lastSelectedPointID) self:ClearPointKeys(moho, mesh:PointID(curve:Point(prewCurvePointId))) end end self.selectedPointID = -1 self.lastSelectedPointID = -1 self.lastPointID = -1 self.isBezierChanged = false self.isLastPointBezierMode = false self.startPoint = 1000000 if self.autoStroke and mesh:IsCurveValid(curve) >= 0 then local shapeID = self:CreateShape(moho, mesh, curve, false) end moho:UpdateUI() else local targetPointID = mesh:CountPoints() - 1 local targetPoint = mesh:Point(targetPointID) local targetCurve, targetWhere = targetPoint:Curve(targetPoint:CountCurves()-1, -1) local targeCurveID = mesh:CurveID(targetCurve) local targetPointCurveID = targetCurve:PointID(targetPoint) local lastCurvePointID = targetPointCurveID local targetCurvePointID = -1 local curveDirection = true if targetCurve:PointID(targetPoint) == 0 then curveDirection = true targetCurvePointID = 0 lastCurvePointID = 1 else curveDirection = false targetCurvePointID = targetCurve:CountPoints()-1 lastCurvePointID = targetCurvePointID - 1 end local lastPoint = targetCurve:Point(lastCurvePointID) if lastPointID == targetPointID and self.lastSelectedPointID ~= -1 then lastPointID = mesh:PointID(targetCurve:Point(targetCurve:PointID(lastPoint)-1)) lastPoint = mesh:Point(lastPointID) end local pt = mesh:Point(drawingClosestID) if ((not self.autoWeld and mouseEvent.altKey) or self.autoWeld and not mouseEvent.altKey) and drawingClosest < self.autoWeldRadius * 1.5 and drawingClosestID ~= self.lastSelectedPointID and self.drawingStatus and not self.isStartPoint and (not mesh:ArePointsAdjacent(drawingClosestID, mesh:PointID(lastPoint)) or not self:ArePointsConnected(moho, mesh, targetPoint, pt))then -- weld point local curve, where = pt:Curve(pt:CountCurves()-1, -1) local originalWeightT = curve:GetWeight(where, moho.layerFrame, true) local originalWeightF = curve:GetWeight(where, moho.layerFrame, false) local originalOffsetT = curve:GetOffset(where, moho.layerFrame, true) local originalOffsetF = curve:GetOffset(where, moho.layerFrame, false) local curveIDpt = pt:CountCurves()-1 local ptEdgeList = self:CollectEdgePoints(moho, mesh, pt) local curvePointID = curve:PointID(pt) local drawingClosestIDDirection = true if #ptEdgeList > 0 then curve, where = pt:Curve(ptEdgeList.curve[1], -1) curveIDpt = ptEdgeList.meshCurveID[1] curvePointID = ptEdgeList[1].curvePointID[1] drawingClosestIDDirection = ptEdgeList.direction[1] end local totalPointsOnCurve = curve:CountPoints() local isEndPoint = pt:IsEndpoint() local closestIdDirection = true if isEndPoint then if curvePointID == 0 then closestIdDirection = true else closestIdDirection = false end end local isOriginalCurveClosed = curve.fClosed local lastPointHandlePt = LM.Vector2:new_local() local lastPointHandlePt2 = LM.Vector2:new_local() lastPointHandlePt:Set(targetCurve:GetControlHandle(lastCurvePointID, moho.layerFrame, true)) lastPointHandlePt2:Set(targetCurve:GetControlHandle(lastCurvePointID, moho.layerFrame, false)) local isEdgePoint = self:IsPointEdge(moho, mesh, pt, false) local arePointsConnected = self:ArePointsConnected(moho, mesh, pt, lastPoint) local handleWeight = curve:GetWeight(curvePointID, moho.layerFrame, false) local handleWeight2 = curve:GetWeight(curvePointID, moho.layerFrame, true) local isPointsOnOneCurve = false isPointsOnOneCurve = self:ArePointsConnected(moho, mesh, pt, targetPoint) local curvePoints = curve:CountPoints() local lastCurve, lastWhere = lastPoint:Curve(lastPoint:CountCurves()-1, -1) local lastCurvesList = {} for i=0, lastPoint:CountCurves()-1 do local testCurve = lastPoint:Curve(i, -1) table.insert(lastCurvesList, testCurve) end local curvesList = {} for i=0, pt:CountCurves()-1 do local testCurve = pt:Curve(i, -1) table.insert(curvesList, testCurve) end local oldCurve = curve local oldLastCurve = lastCurve mesh:WeldPoints(targetPointID, drawingClosestID, moho.layerFrame) pt = mesh:Point(drawingClosestID) moho.layer:UpdateCurFrame() lastCurve, lastWhere = lastPoint:Curve(lastPoint:CountCurves()-1, -1) for i=0, lastPoint:CountCurves()-1 do local testCurve = lastPoint:Curve(i, -1) if pt:IsPointOnCurve(mesh:CurveID(testCurve)) then curve = testCurve lastCurve = testCurve break end end for i=0, pt:CountCurves()-1 do local testCurve = pt:Curve(i, -1) if testCurve == lastCurve then curve = testCurve end end self.handlePt2:Set(pt.fPos) local newCurvePointID = curve:PointID(pt) local ptCurveID = self:FindLastCurvePoint(moho, pt) local newLastCurvePointID = -1 if curveDirection then newLastCurvePointID = lastCurve:PointID(lastPoint) else newLastCurvePointID = self:FindLastCurvePoint(moho, lastPoint) end lastCurve, lastWhere = lastPoint:Curve(lastPoint:CountCurves()-1, -1) curve, where = pt:Curve(pt:CountCurves()-1, -1) newLastCurvePointID = lastWhere ptCurveID = where local isLastCurveReversed = false if isPointsOnOneCurve and curve.fClosed then self.needCreateShape = true self.curveForCreateShape = curve elseif not isEdgePoint and not isEndPoint then elseif isEdgePoint and not isEndPoint then if drawingClosestIDDirection then newLastCurvePointID = totalPointsOnCurve ptCurveID = totalPointsOnCurve -1 if not curveDirection then isLastCurveReversed = true end else newLastCurvePointID = totalPointsOnCurve ptCurveID = curvePointID if not curveDirection then isLastCurveReversed = true end end elseif isEndPoint and not curve.fClosed then if not curveDirection then isLastCurveReversed = true end if self.autoStroke and mesh:IsCurveValid(curve) >= 0 then local shapeID = self:CreateShape(moho, mesh, curve, false) end else if not curveDirection then isLastCurveReversed = true end end self.curvePointID = ptCurveID self.curveIDForMove = mesh:CurveID(curve) if isEndPoint then if (mouseEvent.ctrlKey and not self.sharpCorners) or (not mouseEvent.ctrlKey and self.sharpCorners) then if curve:GetCurvature(ptCurveID, moho.layerFrame) < self.peakedCorner then elseif originalWeightT == 1 and originalWeightF == 1 and originalOffsetT == 0 and originalOffsetF == 0 then curve:SetCurvature(ptCurveID, MOHO.PEAKED + self.peakedCorner, moho.layerFrame) curve:ResetControlHandles(ptCurveID, moho.layerFrame) else if isPointsOnOneCurve then if targetPointCurveID ~= 0 then curve:SetWeight(ptCurveID, 0.02, moho.layerFrame, true) curve:AimControlHandleAtNeighbor(ptCurveID, moho.layerFrame, true) else curve:AimControlHandleAtNeighbor(ptCurveID, moho.layerFrame, false) curve:SetWeight(ptCurveID, 0.02, moho.layerFrame, false) end end end else if (curvePointID == 0 and handleWeight == 0) or (curvePointID > 0 and handleWeight2 == 0) or (curvePointID == 0 and handleWeight == 1) or (curvePointID > 0 and handleWeight2 == 1) then curve:SetCurvature(ptCurveID, self.curvature, moho.layerFrame) curve:ResetControlHandles(ptCurveID, moho.layerFrame) else if curve.fClosed then if targetPointCurveID ~= 0 then local handle = curve:GetControlHandle(ptCurveID, moho.layerFrame, false) local handlePt2 = pt.fPos + (pt.fPos - handle) curve:SetControlHandle(ptCurveID, handlePt2, moho.layerFrame, true, true) else local handle = curve:GetControlHandle(ptCurveID, moho.layerFrame, true) local handlePt2 = pt.fPos + (pt.fPos - handle) curve:SetControlHandle(ptCurveID, handlePt2, moho.layerFrame, false, true) end else local handle = curve:GetControlHandle(ptCurveID, moho.layerFrame, true) local handlePt2 = pt.fPos + (pt.fPos - handle) curve:SetControlHandle(ptCurveID, handlePt2, moho.layerFrame, false, true) end end end else if (mouseEvent.ctrlKey and not self.sharpCorners) or (not mouseEvent.ctrlKey and self.sharpCorners) then if curve:GetCurvature(ptCurveID, moho.layerFrame) < self.peakedCorner then elseif originalWeightT == 1 and originalWeightF == 1 and originalOffsetT == 0 and originalOffsetF == 0 then curve:SetCurvature(ptCurveID, MOHO.PEAKED + self.peakedCorner, moho.layerFrame) curve:ResetControlHandles(ptCurveID, moho.layerFrame) else if isPointsOnOneCurve then if targetPointCurveID ~= 0 then curve:SetWeight(ptCurveID, 0.02, moho.layerFrame, true) curve:AimControlHandleAtNeighbor(ptCurveID, moho.layerFrame, true) else curve:AimControlHandleAtNeighbor(ptCurveID, moho.layerFrame, false) curve:SetWeight(ptCurveID, 0.02, moho.layerFrame, false) end end end else if (curvePointID == 0 and handleWeight == 0) or (curvePointID > 0 and handleWeight2 == 0) or (curvePointID == 0 and handleWeight == 1) or (curvePointID > 0 and handleWeight2 == 1) then curve:SetCurvature(ptCurveID, self.curvature, moho.layerFrame) curve:ResetControlHandles(ptCurveID, moho.layerFrame) else if curve.fClosed then if targetPointCurveID ~= 0 then local handle = curve:GetControlHandle(ptCurveID, moho.layerFrame, false) local handlePt2 = pt.fPos + (pt.fPos - handle) curve:SetControlHandle(ptCurveID, handlePt2, moho.layerFrame, true, true) else local handle = curve:GetControlHandle(ptCurveID, moho.layerFrame, true) local handlePt2 = pt.fPos + (pt.fPos - handle) curve:SetControlHandle(ptCurveID, handlePt2, moho.layerFrame, false, true) end else local handle = curve:GetControlHandle(ptCurveID, moho.layerFrame, true) local handlePt2 = pt.fPos + (pt.fPos - handle) curve:SetControlHandle(ptCurveID, handlePt2, moho.layerFrame, false, true) end end end local handle = curve:GetControlHandle(curve:PointID(pt), moho.layerFrame, true) local handlePt2 = pt.fPos + (pt.fPos - handle) local curvePointID = curve:PointID(pt) local lastPoint = self.selectedPointID end if ptCurveID >= 0 then self.weightTrue = curve:GetWeight(ptCurveID, moho.layerFrame, true) self.weightFalse = curve:GetWeight(ptCurveID, moho.layerFrame, false) end moho:Click() self.statusMode = 1 self.selectedPointID = drawingClosestID self.lastPointID = drawingClosestID self.startPointClick = true self.needCreateNewPoint = false local point = mesh:Point(self.lastPointID) local curveID = self.curveID local segID = -1 local where = -1 local curve if curveID == -1 then if point:IsEndpoint() then curveID, segID = point:GetEndpointEdge(curveID, segID) curve = mesh:Curve(curveID) else curve, where = point:Curve(point:CountCurves()-1, where) curveID = mesh:CurveID(curve) end end self.curveID = curveID local screenPt = LM.Point:new_local() self:ClearPointKeys(moho, self.lastPointID) if self.isFBF and self.isMoho13_5_3 then for i=0, mesh:CountPoints()-1 do local point = mesh:Point(i) for i = 0, point:CountCurves() - 1 do local curve = nil local ptPos = -1 curve, ptPos = point:Curve(i, ptPos) curve:SetCurvature(ptPos, curve:GetCurvature(ptPos, moho.frame), 0) curve:SetWeight(ptPos, curve:GetWeight(ptPos, moho.frame, true), 0, true) curve:SetWeight(ptPos, curve:GetWeight(ptPos, moho.frame, false), 0, false) curve:SetOffset(ptPos, curve:GetOffset(ptPos, moho.frame, true), 0, true) curve:SetOffset(ptPos, curve:GetOffset(ptPos, moho.frame, false), 0, false) curve:DeleteCurvatureKey(ptPos, moho.frame) end end end mesh:PrepFixedHandles(moho.layerFrame) self.isMousePressed = true self.drawingStatus = true self.statusMode = 1 else if drawingClosest > self.autoWeldRadius * 1.5 then if ((self.autoWeld and not mouseEvent.altKey) or (not self.autoWeld and mouseEvent.altKey)) and self.drawingStatus and not self.isStartPoint then local m = LM.Matrix:new_local() local v = LM.Vector2:new_local() local pt = LM.Point:new_local() local curveID = -1 local segID = -1 local pickWidth = 5 moho.drawingLayer:GetFullTransform(moho.layerFrame, m, moho.document) v:Set(mesh:Point(self.selectedPointID).fPos) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) curveID, segID = mesh:Point(self.selectedPointID):GetEndpointEdge(curveID, segID) curveID, segID = moho.view:PickEdge(pt, curveID, segID, pickWidth) if (curveID >= 0 and (self.autoWeld or (not self.autoWeld and mouseEvent.altKey))) then -- add a point in the middle of some curve if (not mesh:Curve(curveID):IsPointOnSegment(self.selectedPointID, segID)) and (not mesh:Curve(curveID):IsPointOnSegment(self.selectedPointID, segID - 1)) and (not mesh:Curve(curveID):IsPointOnSegment(self.selectedPointID, segID + 1)) then local curve = mesh:Curve(curveID) mesh:AddPoint(curve:ClosestPointOnSegment(segID, mesh:Point(self.selectedPointID).fPos, true, true), curveID, segID, moho.layerFrame) mesh:WeldPoints(self.selectedPointID, mesh:CountPoints() - 1, moho.layerFrame) moho:Click() self.drawingStatus = false self.drawWeldPoint = false local newPoint = mesh:Point(mesh:CountPoints() - 1) local curve, where = newPoint:Curve(newPoint:CountCurves()-1, -1) local newPointCurveID = curve:PointID(newPoint) if newPointCurveID ~= 0 then newPointCurveID = curve:CountPoints()-1 end if (mouseEvent.ctrlKey and not self.sharpCorners) or (not mouseEvent.ctrlKey and self.sharpCorners) then curve:SetCurvature(newPointCurveID, MOHO.PEAKED + self.peakedCorner, moho.layerFrame) end if self.autoStroke and mesh:IsCurveValid(curve) >= 0 then local shapeID = self:CreateShape(moho, mesh, curve, false) end self:ClearPointKeys(moho, self.selectedPointID) for i=0, newPoint:CountCurves()-1 do local curve, ptID = newPoint:Curve(i, -1) if curve.fClosed then if ptID + 1 < curve:CountPoints() then self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID + 1))) else self:ClearPointKeys(moho, mesh:PointID(curve:Point(0))) end if ptID - 1 >= 0 then self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID - 1))) else self:ClearPointKeys(moho, mesh:PointID(curve:Point(curve:CountPoints()-1))) end else if ptID + 1 < curve:CountPoints() then self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID + 1))) end if ptID - 1 >= 0 then self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID - 1))) end end end self.selectedPointID = -1 mesh:SelectNone() goto endOfOnClickFunction end end end end ::prepareToCursorDragging:: self.needCreateNewPoint = true self.lastPointID = mesh:CountPoints() - 1 if self.startPointClick and self.targetPointID >= 0 then self.lastPointID = self.targetPointID self.startPointClick = false end local point = mesh:Point(self.lastPointID) local curveID = -1 local segID = -1 local where = -1 local curve if point:IsEndpoint() then curveID, segID = point:GetEndpointEdge(curveID, segID) curve = mesh:Curve(curveID) else curve, where = point:Curve(point:CountCurves()-1, where) curveID = mesh:CurveID(curve) end self.curveID = curveID local screenPt = LM.Point:new_local() point.fAnimPos:SetValue(moho.layerFrame, point.fPos) self:ClearPointKeys(moho, self.lastPointID) local curvePointID = curve:PointID(mesh:Point(self.lastPointID)) if curvePointID > 0 then handle = curve:GetControlHandle(curvePointID, moho.layerFrame, false) else handle = curve:GetControlHandle(curvePointID, moho.layerFrame, true) end mouseEvent.view:Graphics():WorldToScreen(handle, screenPt) self.handlePt2:Set(point.fPos + (point.fPos - handle)) if (mouseEvent.ctrlKey and not self.sharpCorners) or (not mouseEvent.ctrlKey and self.sharpCorners) then point:SetCurvature(MOHO.PEAKED + self.peakedCorner, moho.layerFrame) self.applyPeakedCorner = true else if point:IsEndpoint() then point:SetCurvature(self.curvature, moho.layerFrame) point:ResetControlHandles(moho.layerFrame) end end self.isMousePressed = true self.drawingStatus = true ::endOfOnClickFunction:: end end end ::endOfFunction:: self.lastClickVec:Set(clickVec) if self.fixedHandles then mesh:PrepFixedHandles(moho.layerFrame) self:FixHandles(moho, mesh) end mouseEvent.view:DrawMe() end function MR_CurveTool:OnMouseMoved(moho, mouseEvent) local mesh = moho:DrawingMesh() if (mesh == nil) then return end if (mesh:CountPoints() < 1) then return end if self.isMouseDragging then mouseEvent.view:Graphics():SelectionRect(self.selRect) self.selRect.right = mouseEvent.pt.x self.selRect.bottom = mouseEvent.pt.y mouseEvent.view:Graphics():SelectionRect(self.selRect) mouseEvent.view:RefreshView() mouseEvent.view:DrawMe() return end local frame = moho.layerFrame local clickVec = LM.Vector2:new_local() clickVec:Set(mouseEvent.drawingVec + self.clickOffset) if self.selectedPoints == 1 and not self.drawingStatus then mouseEvent.view:SetCursor(MOHO.moveCursor) end if self.selectedPoints > 1 then if (not self.dragging) then self.centerVec = mesh:SelectedCenter() local mode = self:TestMousePoint(moho, mouseEvent) if (mode == 0) then mouseEvent.view:SetCursor(MOHO.moveCursor) elseif (mode == 1) then mouseEvent.view:SetCursor(MOHO.rotateCursor) elseif (mode == 11) then mouseEvent.view:SetCursor(MOHO.crosshairCursor) elseif (mode >= 20 and mode <= 23) then moho.view:SetCursor(self.skewCursor) elseif (mode >= 24 and mode <= 27) then moho.view:SetCursor(self.distortCursor) elseif (mode >= 2 and mode <= 9) then mouseEvent.view:SetCursor(MOHO.scaleCursor) end mouseEvent.view:DrawMe() return end if (mouseEvent.ctrlKey) then local testVec = LM.Vector2:new_local() testVec:Set(-10000, -10000) if self.prewVec ~= testVec then self.difVec = self.prewVec - mouseEvent.drawingVec end for i=0, mesh:CountPoints()-1 do local pt = mesh:Point(i) if pt.fSelected then local curve = nil local ptPos = -1 for j = 0, pt:CountCurves() - 1 do curve, ptPos = pt:Curve(j, ptPos) local c = curve:GetCurvature(ptPos, moho.layerFrame) c = LM.Clamp(c + self.difVec.x, MOHO.PEAKED + self.peakedCorner, 1) curve:SetCurvature(ptPos, c, moho.layerFrame) end end end mouseEvent.view:DrawMe() self.prewVec:Set(mouseEvent.drawingVec) else if (self.mode == 0) then -- translate self:OnMouseMoved_T(moho, mouseEvent) elseif (self.mode == 1) then -- rotate self:OnMouseMoved_R(moho, mouseEvent) elseif (self.mode == 11) then -- pivot self:OnMouseMoved_P(moho, mouseEvent) elseif (self.mode >= 20 and self.mode <= 23) then -- skew self:OnMouseMoved_Skew(moho, mouseEvent) elseif (self.mode >= 24 and self.mode <= 27) then -- distord self:OnMouseMoved_Distort(moho, mouseEvent) else -- scale self:OnMouseMoved_S(moho, mouseEvent) end end return end if not self.drawingStatus then if moho.drawingLayer:CurrentAction() ~= "" then moho.view:SetCursor(MOHO.moveCursor) end return end self.closestID = -1 self.closest = 1e6 local pt = mesh:Point(self.selectedPointID) if self.dragPoint and self.movePoints then self.transformation = true local testVec = LM.Vector2:new_local() testVec:Set(-10000, -10000) if self.prewVec ~= testVec then self.difVec = self.prewVec - clickVec end if mouseEvent.ctrlKey then local curve = nil local ptPos = -1 for j = 0, pt:CountCurves() - 1 do curve, ptPos = pt:Curve(j, ptPos) local c = curve:GetCurvature(ptPos, moho.layerFrame) c = LM.Clamp(c + self.difVec.x + self.difVec.y, MOHO.PEAKED + self.peakedCorner, 1) curve:SetCurvature(ptPos, c, moho.layerFrame) end moho:AddPointKeyframe(moho.layerFrame, moho.layer) mouseEvent.view:DrawMe() self.prewVec:Set(mouseEvent.drawingVec + self.clickOffset) return end if not (self.handleSide ~= 0) then if not mouseEvent.ctrlKey then local curVec = mouseEvent.drawingVec - mouseEvent.drawingStartVec if (mouseEvent.shiftKey) then if (math.abs(mouseEvent.drawingVec.x - mouseEvent.drawingStartVec.x) > math.abs(mouseEvent.drawingVec.y - mouseEvent.drawingStartVec.y)) then curVec.y = 0 else curVec.x = 0 end end if (moho.gridOn) then moho:SnapToGrid(curVec) end mesh:TranslatePoints(curVec) self:AddPointKeyframe(moho, frame, moho.drawingLayer) if self.fixedHandles and not mouseEvent.altKey then mesh:PreserveHandlePositions(frame) end end mouseEvent.view:DrawMe() self.prewVec:Set(mouseEvent.drawingVec + self.clickOffset) if ((self.autoWeld and not mouseEvent.altKey) or (not self.autoWeld and mouseEvent.altKey)) and pt:IsEndpoint() then self:PreviewWeldPoint(moho, mouseEvent, pt) else self.drawWeldPoint = false end return else if self.selectedPoints == 1 then local newVal = (mouseEvent.pt.x - mouseEvent.startPt.x) / mouseEvent.view:Graphics():Width() if (self.handleSide ~= 0) then local curve = mesh:Curve(self.handleCurveID) local syncHandles = true if (mouseEvent.altKey) then syncHandles = false end local handlePt = self.startHandle + (mouseEvent.vec - mouseEvent.startVec) if (moho.gridOn) then moho:SnapToGrid(handlePt) end if (math.abs(curve:GetCurvature(self.handlePointID, moho.layerFrame)) < 0.001) then curve:SetCurvature(self.handlePointID, 0.001, moho.layerFrame) end local oldOffset = curve:GetOffset(self.handlePointID, moho.layerFrame, (self.handleSide == -1)) local oldOppOffset = curve:GetOffset(self.handlePointID, moho.layerFrame, (self.handleSide == 1)) if math.abs(oldOffset - oldOppOffset) > 0.01 then syncHandles = false end local newVector = handlePt - self.startFPos local weightMultiply = newVector:Mag()/self.startVectorMag local angleAdd = AE_Utilities:GetAngleBetween(self.startVector, newVector) if self.flipDirection then angleAdd = -angleAdd end local newOffset = self.startOffset + angleAdd local newWeight = newVector:Mag()/self.weightMultiplier - self.weightDelta newWeight = newWeight - self.weightStartDelta curve:SetWeight(self.handlePointID, newWeight, moho.layerFrame, (self.handleSide == -1)) curve:SetOffset(self.handlePointID, newOffset, moho.layerFrame, (self.handleSide == -1)) if syncHandles then curve:SetOffset(self.handlePointID, newOffset, moho.layerFrame, (self.handleSide == 1)) end end end self.savedVal = newVal moho.drawingLayer:UpdateCurFrame() mouseEvent.view:DrawMe() self.prewVec:Set(mouseEvent.drawingVec + self.clickOffset) return end end self.prewVec:Set(mouseEvent.drawingVec) mouseEvent.view:SetCursor(MOHO.crosshairCursor) if moho.drawingLayer:CurrentAction() ~= "" then moho.view:SetCursor(MOHO.moveCursor) return end if self.singleCurveMode then local clickVec = LM.Vector2:new_local() clickVec:Set(mouseEvent.drawingVec + self.clickOffset) self.transformation = true if self.step == 1 and self.secondPointID >= 0 then local secondPoint = mesh:Point(self.secondPointID) if secondPoint then if mouseEvent.shiftKey then if (math.abs(mouseEvent.drawingVec.x - mouseEvent.drawingStartVec.x) > math.abs(mouseEvent.drawingVec.y - mouseEvent.drawingStartVec.y)) then clickVec.y = secondPoint.fTempPos.y else clickVec.x = secondPoint.fTempPos.x end end secondPoint.fPos:Set(clickVec) if clickVec ~= secondPoint.fTempPos then self.pointPoseChanged = true end if (moho.gridOn) then moho:SnapToGrid(secondPoint.fPos) end if not self.isNewCurve then mesh:PreserveHandlePositions(moho.layerFrame) end self:PreviewWeldPoint(moho, mouseEvent, secondPoint) mouseEvent.view:DrawMe() end elseif self.step == 2 and self.firstPointID >= 0 and self.secondPointID >= 0 then local firstPoint = mesh:Point(self.firstPointID) local secondPoint = mesh:Point(self.secondPointID) if secondPoint and firstPoint then local curve, where = secondPoint:Curve(secondPoint:CountCurves()-1, -1) local curve2, where2 = firstPoint:Curve(firstPoint:CountCurves()-1, -1) local firstHandle = LM.Vector2:new_local() local secondHandle = LM.Vector2:new_local() local firstHandleDelta = LM.Vector2:new_local() local secondHandleDelta = LM.Vector2:new_local() local curveCenter = LM.Vector2:new_local() local firstHandleNewPos = LM.Vector2:new_local() local secondHandleNewPos = LM.Vector2:new_local() local curvature = self.curvatureSC * 2 firstHandle:Set(firstPoint.fPos) secondHandle:Set(secondPoint.fPos) curveCenter:Set(firstHandle + (secondHandle - firstHandle) / 2) local distance = MR_Utilities:GetDistance(curveCenter, clickVec) firstHandleNewPos:Set((secondHandle - firstHandle) / 2) secondHandleNewPos:Set((secondHandle - firstHandle) / 2) secondHandleDelta:Set(clickVec.x + (firstHandleNewPos.x * curvature), clickVec.y + (firstHandleNewPos.y * curvature)) firstHandleDelta:Set(clickVec.x - (secondHandleNewPos.x * curvature), clickVec.y - (secondHandleNewPos.y * curvature)) firstHandle:Set(firstHandleDelta) secondHandle:Set(secondHandleDelta) if curve.fClosed then curve:SetControlHandle(where2, firstHandle, moho.layerFrame, where > where2, false) curve:SetControlHandle(where, secondHandle, moho.layerFrame, where2 > where, false) else curve:SetControlHandle(where2, firstHandle, moho.layerFrame, where2 > where, false) curve:SetControlHandle(where, secondHandle, moho.layerFrame, where > where2, false) end mouseEvent.view:DrawMe() end end return end if self.isMousePressed and not self.isStartPoint then local g = mouseEvent.view:Graphics() g:Push() local matrix = LM.Matrix:new_local() moho.drawingLayer:GetFullTransform(moho.layerFrame, matrix, moho.document) g:ApplyMatrix(matrix) local currentScale = g:CurrentScale(false) g:Pop() local mouseDist = MR_Utilities:GetDistance(mouseEvent.drawingStartVec, mouseEvent.drawingVec) mouseDist = mouseDist * currentScale if self.lastPointID >= 0 and not self.applyPeakedCorner then if (mouseDist > self.threshold or self.isBezierChanged) and self.useBezierHandles then local point = mesh:Point(self.lastPointID) local curveID = -1 local segID = -1 local where = -1 local curve if point:IsEndpoint() then curveID, segID = point:GetEndpointEdge(curveID, segID) curve = mesh:Curve(curveID) else curve, where = point:Curve(point:CountCurves()-1, where) end if self.curveIDForMove >= 0 then curve = mesh:Curve(self.curveIDForMove) end if not self.isBezierChanged then local testStartID local curvePointID = curve:PointID(point) if curvePointID == 0 then testStartID = mesh:PointID(curve:Point(1)) elseif curvePointID > 0 then testStartID = mesh:CountPoints() - 2 end self.selectedCurvePointID = ptCurveID if self.startCurvePointID > -1 and testStartID > -1 and not self.isLastPointBezierMode then if self.startCurvePointID == testStartID then local startCurvePoint = mesh:Point(self.startCurvePointID) local startCurvePointID = curve:PointID(startCurvePoint) if startCurvePointID == 0 then startCurvePointID = mesh:PointID(curve:Point(1)) elseif startCurvePointID > 0 then startCurvePointID = self:FindLastCurvePoint(moho, startCurvePoint) end local startCurvePointID = self:FindLastCurvePoint(moho, startCurvePoint) if curvePointID == 0 then curve:SetControlHandle(startCurvePointID, startCurvePoint.fPos, moho.layerFrame, true, true) elseif curvePointID > 0 then curve:SetControlHandle(startCurvePointID, startCurvePoint.fPos, moho.layerFrame, false, true) end end end end self.isBezierChanged = true self.curveID = curveID local curvePoint = curve:PointID(point) if self.curvePointID == -1 then if point:IsEndpoint() then self.curvePointID = curve:PointID(point) else if curvePoint == 0 then self.curvePointID = curvePoint else self.curvePointID = self:FindLastCurvePoint(moho, point) end end end self.meshPointID = self.lastPointID self.handlePt:Set(mouseEvent.vec) if not mouseEvent.altKey then self.handlePt2:Set(point.fPos + (point.fPos - mouseEvent.vec)) end self.midPt:Set(point.fPos) if point:IsEndpoint() then if curve:CountPoints() == 2 then local firstCurvePoint = 0 if curvePoint == 0 then firstCurvePoint = 1 end if curve:GetWeight(firstCurvePoint, moho.frame, firstCurvePoint > 0) == 1 then curve:SetWeight(firstCurvePoint, 0, moho.frame, firstCurvePoint > 0) self.correctFirstHandle = true end end if curvePoint == 0 then curve:SetControlHandle(self.curvePointID, self.handlePt, moho.layerFrame, true, not mouseEvent.altKey) if not mouseEvent.altKey then curve:SetControlHandle(self.curvePointID, self.handlePt2, moho.layerFrame, false, not mouseEvent.altKey) end else curve:SetControlHandle(self.curvePointID, self.handlePt, moho.layerFrame, false, not mouseEvent.altKey) if not mouseEvent.altKey then curve:SetControlHandle(self.curvePointID, self.handlePt2, moho.layerFrame, true, not mouseEvent.altKey) end end else if not mouseEvent.altKey then self.handlePt2:Set(mouseEvent.vec) end self.handlePt:Set(point.fPos + (point.fPos - mouseEvent.vec)) if curve.fClosed then self.curvePointID = curve:PointID(point) end local areAdjacentPoints = false local curvePoints = curve:CountPoints() if curve.fClosed then areAdjacentPoints = true else if self.curvePointID ~= curvePoints -1 and self.curvePointID ~= 0 then areAdjacentPoints = true end end if areAdjacentPoints then if self.curvePointID == 0 then curve:SetControlHandle(self.curvePointID, self.handlePt, moho.layerFrame, true, not mouseEvent.altKey) if not mouseEvent.altKey then curve:SetControlHandle(self.curvePointID, self.handlePt2, moho.layerFrame, false, not mouseEvent.altKey) end if mouseEvent.shiftKey then curve:SetWeight(self.curvePointID, self.weightTrue, moho.layerFrame, false) end else curve:SetControlHandle(self.curvePointID, self.handlePt, moho.layerFrame, false, not mouseEvent.altKey) if not mouseEvent.altKey then curve:SetControlHandle(self.curvePointID, self.handlePt2, moho.layerFrame, true, not mouseEvent.altKey) end if mouseEvent.shiftKey then curve:SetWeight(self.curvePointID, self.weightFalse, moho.layerFrame, true) end end else if self.curvePointID == 0 then curve:SetControlHandle(self.curvePointID, self.handlePt2, moho.layerFrame, true, not mouseEvent.altKey) if not mouseEvent.altKey then curve:SetControlHandle(self.curvePointID, self.handlePt, moho.layerFrame, false, not mouseEvent.altKey) end if mouseEvent.shiftKey then curve:SetWeight(self.curvePointID, self.weightTrue, moho.layerFrame, false) end else curve:SetControlHandle(self.curvePointID, self.handlePt2, moho.layerFrame, false, not mouseEvent.altKey) if not mouseEvent.altKey then curve:SetControlHandle(self.curvePointID, self.handlePt, moho.layerFrame, true, not mouseEvent.altKey) end if mouseEvent.shiftKey then curve:SetWeight(self.curvePointID, self.weightFalse, moho.layerFrame, true) end end end end if self.isLastPointBezierMode then mesh:PreserveHandlePositions(moho.layerFrame) end end end else if self.isBezierChanged and self.isMousePressed or not self.isMousePressed then local clickVec = LM.Vector2:new_local() clickVec:Set(mouseEvent.drawingVec) if (mouseEvent.shiftKey and not self.isFirstClick) then if (math.abs(mouseEvent.drawingVec.x - pt.fTempPos.x) > math.abs(mouseEvent.drawingVec.y - pt.fTempPos.y)) then clickVec.y = pt.fTempPos.y else clickVec.x = pt.fTempPos.x end end pt.fPos:Set(clickVec) if moho.gridOn and not self.isFirstClick then moho:SnapToGrid(pt.fPos) end end if ((self.autoWeld and not mouseEvent.altKey) or (not self.autoWeld and mouseEvent.altKey)) and pt:IsEndpoint() then self:PreviewWeldPoint(moho, mouseEvent, pt) else self.drawWeldPoint = false end if self.isStartPoint then local g = mouseEvent.view:Graphics() g:Push() local matrix = LM.Matrix:new_local() moho.drawingLayer:GetFullTransform(moho.layerFrame, matrix, moho.document) g:ApplyMatrix(matrix) local currentScale = g:CurrentScale(false) g:Pop() local mouseDist = MR_Utilities:GetDistance(mouseEvent.drawingStartVec, mouseEvent.drawingVec) mouseDist = mouseDist * currentScale if self.startCurvePointID >= 0 and not self.applyPeakedCorner then if (mouseDist > self.threshold or self.isBezierChanged and self.isMousePressed) and self.useBezierHandles then self.isBezierChanged = true local point = mesh:Point(self.startCurvePointID) local startPoint = mesh:Point(self.startCurvePointID) local curveID = -1 local segID = -1 local where = -1 local curve if point:IsEndpoint() then curveID, segID = point:GetEndpointEdge(curveID, segID) curve = mesh:Curve(curveID) else curve, where = point:Curve(point:CountCurves()-1, where) end self.curveID = mesh:CurveID(curve) self.curvePointID = curve:PointID(point) self.midPt:Set(startPoint.fPos) self.handlePt:Set(mouseEvent.vec) if not mouseEvent.altKey then self.handlePt2:Set(startPoint.fPos + (startPoint.fPos - mouseEvent.vec)) end local curvePointID = curve:PointID(mesh:Point(self.lastPointID)) local curvePoint = curve:PointID(point) local curvePoints = curve:CountPoints() if curvePoint == 0 then for i = 0, curvePoints-1 do local curvePoint = curve:Point(curvePoints - i) if curvePoint == point then self.curvePointID = i break end end else for i = 0, curvePoints-1 do local curvePoint = curve:Point(curvePoints - i) if curvePoint == point then self.curvePointID = curvePoints - i break end end end if self.isMousePressed then if curvePointID == 0 then curve:SetControlHandle(self.curvePointID, self.handlePt, moho.layerFrame, true, not mouseEvent.altKey) curve:SetControlHandle(self.curvePointID, self.handlePt2, moho.layerFrame, false, not mouseEvent.altKey) else curve:SetControlHandle(self.curvePointID, self.handlePt, moho.layerFrame, false, not mouseEvent.altKey) curve:SetControlHandle(self.curvePointID, self.handlePt2, moho.layerFrame, true, not mouseEvent.altKey) end end end end end if self.isLastPointBezierMode then mesh:PreserveHandlePositions(moho.layerFrame) end moho:AddPointKeyframe(moho.layerFrame, moho.layer) end mouseEvent.view:DrawMe() end function MR_CurveTool:OnMouseUp(moho, mouseEvent) local mesh = moho:DrawingMesh() if (mesh == nil) then return end local shapeID = -1 self.selectedPoints = moho:CountSelectedPoints() if self.isMouseDragging then local v = LM.Vector2:new_local() local screenPt = LM.Point:new_local() local m = LM.Matrix:new_local() if not (mouseEvent.shiftKey or mouseEvent.altKey) then mesh:SelectNone() end local id = mouseEvent.view:PickPoint(mouseEvent.pt) if id ~= -1 then mesh:Point(id).fSelected = not (self.selectedPoints > 1 and mouseEvent.altKey and mouseEvent.ctrlKey and not mouseEvent.shiftKey) if not mouseEvent.shiftKey and mouseEvent.altKey and mouseEvent.ctrlKey then mesh:Point(id).fSelected = false end end self.selRect:Normalize() moho.drawingLayer:GetFullTransform(moho.layerFrame, m, moho.document) for i = 0, mesh:CountPoints() - 1 do local pt = mesh:Point(i) if (not pt.fHidden) then v:Set(pt.fPos) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, screenPt) if (self.selRect:Contains(screenPt)) then pt.fSelected = not (self.selectedPoints > 1 and mouseEvent.altKey and mouseEvent.ctrlKey and not mouseEvent.shiftKey) if not mouseEvent.shiftKey and mouseEvent.altKey and mouseEvent.ctrlKey then pt.fSelected = false end end end end self.isMouseDragging = false self.selectedPoints = moho:CountSelectedPoints() if self.selectedPoints == 0 and moho.frame == 0 then mouseEvent.view:SetCursor(MOHO.crosshairCursor) end local isDrawingEnabled = true if not self.drawInZeroFrame and moho.frame == 0 or not self.drawInNonZeroFrame and moho.frame ~= 0 then isDrawingEnabled = false end if self.isFBF and self.alwaysDrawOnFBF then isDrawingEnabled = true end local arePointsSelected = false for i=0, mesh:CountPoints()-1 do local point = mesh:Point(i) if point.fSelected then arePointsSelected = true break end end if not arePointsSelected and not isDrawingEnabled then self:SingleClickSelect(moho, mouseEvent, false, true) end mouseEvent.view:DrawMe() moho.drawingLayer:UpdateCurFrame() return end if self.isCurveEnded and self.dragPoint and self.movePoints then return end if self.selectedPoints > 1 then if self.outside and not self.transformation then mesh:SelectNone() self.dragging = false return end if (self.mode ~= 11) then moho:NewKeyframe(CHANNEL_POINT) moho:UpdateUI() if (self.mode == 0) then elseif (self.mode == 1) then local v = mesh:SelectedCenter() self.pivotOffset = self.centerVec - v end end self.selID = -1 self.dragging = false self:AddPointKeyframe(moho, moho.layerFrame) if self.fixedHandles and self.transformation then self:RepairFixedHandles(moho, mesh) end if self.isFBF then self:FixFBF(moho) end moho.layer:UpdateCurFrame() moho:UpdateUI() return end local bezierMode = false if self.dragPoint and self.movePoints and self.selectedPoints == 1 then if self.transformation then local point = mesh:Point(self.selectedPointID) self.weldedCurve = nil if self:WeldPoints(moho, mouseEvent, point.fPos, false) then if self.weldedCurve then shapeID = self:CreateShape(moho, mesh, self.weldedCurve, true) end if self.isFBF then self:FixFBF(moho) end moho.layer:UpdateCurFrame() moho:UpdateUI() return end end if self.handleSide == 0 and self.transformation then self:AddPointKeyframe(moho, moho.layerFrame, nil, MOHO.MohoGlobals.EditMultipleKeys) end if self.fixedHandles and self.transformation then self:RepairFixedHandles(moho, mesh) end self.selectedPointID = - 1 self.doNotAddNewPoint = true self.drawingStatus = false self.drawWeldPoint = false if self.createdMidPoint then mesh:SelectNone() self.createdMidPoint = false end if self.isFBF and self.transformation then self:FixFBF(moho) end moho.layer:UpdateCurFrame() moho:UpdateUI() return end if moho.drawingLayer:CurrentAction() ~= "" then return end if self.singleCurveMode then if self.step == 1 then if not self.transformation then self.step = 0 self.drawingStatus = false moho.document:Undo() moho:UpdateUI() moho.layer:UpdateCurFrame() moho:UpdateSelectedChannels() mouseEvent.view:DrawMe() return end self.step = 2 local firstPoint = mesh:Point(self.firstPointID) local secondPoint = mesh:Point(self.secondPointID) if secondPoint and firstPoint then local closestID = -1 local closest = 1e6 local testVec1 = LM.Vector2:new_local() testVec1:Set(secondPoint.fPos) closestID = mesh:ClosestPoint(testVec1) secondPoint.fAnimPos:SetValue(moho.layerFrame, secondPoint.fPos) self:ClearPointKeys(moho, self.firstPointID) self:ClearPointKeys(moho, self.secondPointID) if closestID >= 0 then if self.autoWeld then if self:WeldPoints(moho, mouseEvent, secondPoint.fPos, false) then self.isWelded = true self.selectedPointID = self.secondPointID self:ClearPointKeys(moho, self.secondPointID) end end end end elseif self.step == 2 then self.drawingStatus = false local firstPoint = mesh:Point(self.firstPointID) local secondPoint = mesh:Point(self.secondPointID) if secondPoint and firstPoint then mesh:SelectNone() firstPoint.fSelected = true secondPoint.fSelected = true MOHO:SplitSelectedSegments(mesh, self.points, moho.layerFrame) if (moho.frame > 0) then for i=0, mesh:CountPoints()-1 do local point = mesh:Point(i) if point.fSelected then self:ClearPointKeys(moho, i) end end end if self.isWelded then self:CreateShape(moho, mesh, self.weldedCurve, true) end self.isWelded = false end mesh:SelectNone() if self.isFBF then self:FixFBF(moho) end self.step = 0 end moho:UpdateUI() moho.layer:UpdateCurFrame() moho:UpdateSelectedChannels() mouseEvent.view:DrawMe() return end if self.selectedPointID >= 0 and not self.isStartPoint and self.statusMode == 0 then if self.needCreateNewPoint then local pt = mesh:Point(self.selectedPointID) local curve = mesh:Curve(self.curveID) local lastCurveID = curve:PointID(mesh:Point(self.lastPointID)) local curvePointID = lastCurveID -1 local startCurvePoint = false local startCurvePointOnCurveID = -1 local fixFirstEdgePoint = false if curvePointID == 0 then startCurvePoint = true startCurvePointOnCurveID = curvePointID elseif lastCurveID == 0 and curve:CountPoints() == 2 then fixFirstEdgePoint = true end local needCorrectHandles = false local handle1 = LM.Vector2:new_local() local handle2 = LM.Vector2:new_local() local startHandle = LM.Vector2:new_local() if startCurvePoint then if curve:CountPoints() == 2 then handle1 = curve:GetControlHandle(0, moho.layerFrame, false) handle2 = curve:GetControlHandle(1, moho.layerFrame, true) needCorrectHandles = true end if startCurvePointOnCurveID >= 0 then startHandle = curve:GetControlHandle(startCurvePointOnCurveID, moho.layerFrame, true) end end local newPoint local edgeHandlePt local edgeHandlePt2 local clickPointID = self.selectedPointID self:ClearPointKeys(moho, self.lastSelectedPointID) if not self.doNotAddNewPoint then local fromStart = false if lastCurveID ~= curve:CountPoints()-1 then curvePointID = curve:CountPoints() - lastCurveID - 1 fromStart = true end local handlePt = curve:GetControlHandle(curvePointID, moho.layerFrame, false) local handlePt2 = curve:GetControlHandle(curvePointID, moho.layerFrame, true) mesh:AddPoint(mouseEvent.drawingVec, self.selectedPointID, moho.layerFrame) if fromStart then curvePointID = curvePointID +1 end self.lastSelectedPointID = self.selectedPointID self.selectedPointID = mesh:CountPoints() - 1 newPoint = mesh:Point(self.selectedPointID) newPoint.fTempPos:Set(pt.fPos) mesh:SelectNone() newPoint.fSelected = true newPoint:ResetControlHandles(moho.layerFrame) else self.lastSelectedPointID = self.selectedPointID self.selectedPointID = mesh:CountPoints() - 1 end if self.startPointClick then local clickPoint = mesh:Point(clickPointID) clickPoint:ResetControlHandles(moho.layerFrame) self.startPoint = self.selectedPointID self.startPointClick = false end if self.isMousePressed and not self.applyPeakedCorner and self.isBezierChanged then local curvePointID = curve:PointID(mesh:Point(self.lastPointID)) local curveNewPointID = curve:PointID(mesh:Point(self.selectedPointID)) if curvePointID == 1 and curveNewPointID == 0 then curve:SetControlHandle(curvePointID, self.handlePt2, moho.layerFrame, false, not mouseEvent.altKey) curve:SetControlHandle(curvePointID, self.handlePt, moho.layerFrame, true, not mouseEvent.altKey) else curve:SetControlHandle(curvePointID, self.handlePt2, moho.layerFrame, true, not mouseEvent.altKey) curve:SetControlHandle(curvePointID, self.handlePt, moho.layerFrame, false, not mouseEvent.altKey) end if needCorrectHandles then if self.correctFirstHandle then curve:SetWeight(0, 1, moho.layerFrame, false) self.correctFirstHandle = false end curve:SetControlHandle(1, handle2, moho.layerFrame, true, true) self:ClearPointKeys(moho, mesh:PointID(curve:Point(0))) self:ClearPointKeys(moho, mesh:PointID(curve:Point(1))) else if startCurvePoint then if not startCurvePoint:IsEndpoint() and curvePointID - 1 == curveNewPointID and startCurvePointOnCurveID >= 0 then curve:SetControlHandle(startCurvePointOnCurveID, startHandle, moho.layerFrame, true, true) end end end if fixFirstEdgePoint then if self.correctFirstHandle then curve:SetWeight(2, 1, moho.layerFrame, true) self:ClearPointKeys(moho, mesh:PointID(curve:Point(2))) self.correctFirstHandle = false end end if (mouseEvent.ctrlKey and not self.sharpCorners) or (not mouseEvent.ctrlKey and self.sharpCorners) then if curveNewPointID == 0 then curve:SetWeight(curvePointID, MOHO.PEAKED + self.peakedCorner, moho.layerFrame, true) else curve:SetWeight(curvePointID, MOHO.PEAKED + self.peakedCorner, moho.layerFrame, false) end end self:ClearPointKeys(moho, self.selectedPointID) self:ClearPointKeys(moho, self.lastSelectedPointID) self:ClearPointKeys(moho, self.lastPointID) mesh:PrepFixedHandles(moho.layerFrame) else if needCorrectHandles then if not self.firstPointSharpCorner then curve:SetCurvature(0, self.curvature, moho.layerFrame) end end if fixFirstEdgePoint then if not self.firstPointSharpCorner then curve:SetCurvature(2, self.curvature, moho.layerFrame) end end self:ClearPointKeys(moho, mesh:PointID(curve:Point(0))) self:ClearPointKeys(moho, mesh:PointID(curve:Point(2))) end self.firstPointSharpCorner = false self:ClearPointKeys(moho, self.selectedPointID) self:ClearPointKeys(moho, self.lastSelectedPointID) self:ClearPointKeys(moho, self.lastPointID) self.drawingStatus = true end elseif self.isStartPoint and self.statusMode == 0 then local pt = mesh:Point(self.startCurvePointID) local secondPoint = mesh:Point(mesh:CountPoints() - 1) local curve = mesh:Curve(self.curveID) local secondPointID = curve:PointID(secondPoint) if self.isMousePressed and not self.applyPeakedCorner and self.isBezierChanged then local curvePointID = curve:PointID(mesh:Point(mesh:CountPoints() - 1)) curve:SetCurvature(curvePointID, self.curvature, moho.layerFrame) curve:SetCurvature(curve:PointID(pt), self.curvature, moho.layerFrame) if curvePointID == 0 then curve:SetControlHandle(self.curvePointID, self.handlePt, moho.layerFrame, true, not mouseEvent.altKey) curve:SetControlHandle(self.curvePointID, self.handlePt2, moho.layerFrame, false, not mouseEvent.altKey) else curve:SetControlHandle(self.curvePointID, self.handlePt, moho.layerFrame, false, not mouseEvent.altKey) curve:SetControlHandle(self.curvePointID, self.handlePt2, moho.layerFrame, true, not mouseEvent.altKey) end curve:SetControlHandle(secondPointID, secondPoint.fPos, moho.layerFrame, true, true) curve:SetControlHandle(secondPointID, secondPoint.fPos, moho.layerFrame, false, true) moho:NewKeyframe(CHANNEL_CURVE) else secondPoint:ResetControlHandles(moho.layerFrame) end self.selectedPointID = mesh:CountPoints() - 1 self:ClearPointKeys(moho, self.startCurvePointID) self:ClearPointKeys(moho, self.selectedPointID) local point = mesh:Point(self.selectedPointID) local pointsOnCurve = curve:CountPoints() if self.isMoho13_5_3 and moho.drawingFrame > 0 then if pointsOnCurve > 2 then local curve, ptPos = point:Curve(point:CountCurves()-1, -1) for p=0, pointsOnCurve-1 do curve:DeleteCurvatureKey(p, moho.layerFrame) end end end mesh:PrepFixedHandles(moho.layerFrame) elseif self.statusMode == 1 then local curveClosed = self.needCreateShape if self.autoFill or self.autoStroke then if self.needCreateShape and self.curveForCreateShape then shapeID = self:CreateShape(moho, mesh, self.curveForCreateShape, true) self.needCreateShape = false end end mesh:SelectNone() self.drawingStatus = false self.drawWeldPoint = false self:ClearPointKeys(moho, self.selectedPointID) self:ClearPointKeys(moho, self.lastSelectedPointID) self:ClearPointKeys(moho, self.lastPointID) local selectedPoint = mesh:Point(self.selectedPointID) if moho.drawingFrame > 0 then if not curveClosed then for c=0, selectedPoint:CountCurves()-1 do local curve = selectedPoint:Curve(c, -1) if curve ~= nil then for ptPos=0, curve:CountPoints()-1 do curve:SetCurvature(ptPos, curve:GetCurvature(ptPos, moho.layerFrame), 0) curve:SetWeight(ptPos, curve:GetWeight(ptPos, moho.layerFrame, true), 0, true) curve:SetWeight(ptPos, curve:GetWeight(ptPos, moho.layerFrame, false), 0, false) curve:SetOffset(ptPos, curve:GetOffset(ptPos, moho.layerFrame, true), 0, true) curve:SetOffset(ptPos, curve:GetOffset(ptPos, moho.layerFrame, false), 0, false) if self.isMoho13_5_3 then curve:DeleteCurvatureKey(ptPos, moho.layerFrame) end end end end end mesh:PrepFixedHandles(moho.layerFrame) end self.selectedPointID = -1 end self.handlePt:Set(10000,10000) self.handlePt2:Set(10000,10000) self.midPt:Set(10000,10000) if self.isBezierChanged or bezierMode then self.isLastPointBezierMode = true else self.isLastPointBezierMode = false end self.isMousePressed = false self.isBezierChanged = false self.isFirstClick = false self.targetPointID = -1 if self.selectedPoints == 0 and moho.frame == 0 then mouseEvent.view:SetCursor(MOHO.crosshairCursor) end if shapeID >= 0 then local shape = mesh:Shape(shapeID) shape.fSelected = true end moho:UpdateUI() moho.layer:UpdateCurFrame() moho:UpdateSelectedChannels() mouseEvent.view:DrawMe() end function MR_CurveTool:OnKeyDown(moho, keyEvent) local mesh = moho:DrawingMesh() if (mesh == nil) then return end if ((keyEvent.keyCode == LM.GUI.KEY_DELETE) or (keyEvent.keyCode == LM.GUI.KEY_BACKSPACE)) then if (not keyEvent.view:IsMouseDragging()) and not self.drawingStatus then moho.document:PrepUndo(moho.drawingLayer) moho.document:SetDirty() MOHO.DeleteSelectedPoints(mesh) self.selectedPoints = moho:CountSelectedPoints() keyEvent.view:DrawMe() end end if keyEvent.keyCode == LM.GUI.KEY_BIND then if self.drawingStatus and not (self.step == 1 or self.step == 2) then self.weldedCurve = nil local point = mesh:Point(self.selectedPointID) local shapeID = -1 local lastPoint = mesh:Point(self.selectedPointID) local curve, where = point:Curve(point:CountCurves()-1, -1) local prewPoint = curve:Point(curve:CountPoints()-2) if self:WeldPoints(moho, keyEvent, point.fPos, true) then if self.weldedCurve then shapeID = self:CreateShape(moho, mesh, self.weldedCurve, true) end self:ClearPointKeys(moho, self.selectedPointID) self:ClearPointKeys(moho, self.lastSelectedPointID) self:ClearPointKeys(moho, self.lastPointID) self.drawingStatus = false self.drawWeldPoint = false self:CloseCurve(moho, prewPoint) self.selectedPointID = -1 self.startPoint = -1 mesh:SelectNone() if shapeID >= 0 then local shape = mesh:Shape(shapeID) shape.fSelected = true end moho:UpdateUI() moho.layer:UpdateCurFrame() moho:UpdateSelectedChannels() moho.view:DrawMe() return end local point = mesh:Point(self.selectedPointID) self:CloseCurve(moho, point) end elseif keyEvent.keyCode == 27 or keyEvent.keyCode == -51 then if self.step == 1 or self.step == 2 then if self.step == 1 and self.selectedPointID > -1 then mesh:DeletePoint(self.selectedPointID) self:ClearPointKeys(moho, self.selectedPointID) elseif self.step == 2 then moho.document:Undo() end if self.isFBF then self:FixFBF(moho) end self.step = 0 self.drawingStatus = false mesh:SelectNone() else local curveEnded = false if self.drawingStatus and self.selectedPointID >= 0 then local point = mesh:Point(self.selectedPointID) if point:IsEndpoint() and not (self.dragPoint and self.movePoints) then if self.targetPointID < 0 and not self.isMousePressed then local lastPoint = mesh:Point(self.selectedPointID) local curve, where = point:Curve(point:CountCurves()-1, -1) local prewPoint = curve:Point(curve:CountPoints()-2) mesh:DeletePoint(self.selectedPointID) if prewPoint then self:CloseCurve(moho, prewPoint) end end end end if not curveEnded then self:CloseCurve(moho) end end elseif keyEvent.keyCode == LM.GUI.KEY_BACKSPACE then local endPointID = mesh:CountPoints() -1 if endPointID >= self.startPoint and self.drawingStatus then local endPoint = mesh:Point(endPointID) mesh:DeletePoint(endPointID) endPointID = mesh:CountPoints() -1 if endPointID == self.startPoint then local endPoint = mesh:Point(endPointID) mesh:DeletePoint(endPointID) end if mesh:CountPoints() -1 >= self.startPoint then self.selectedPointID = mesh:CountPoints() -1 local point = mesh:Point(self.selectedPointID) point:ResetControlHandles(moho.layerFrame) self:ClearPointKeys(moho, self.selectedPointID) moho.layer:UpdateCurFrame() keyEvent.view:DrawMe() else self.selectedPointID = -1 self.drawingStatus = false self.drawWeldPoint = false moho.layer:UpdateCurFrame() keyEvent.view:DrawMe() moho:UpdateUI() end self.lastClickVec:Set(100000, 100000) end end end function MR_CurveTool:OnKeyUp(moho, keyEvent) end function MR_CurveTool:DrawMe(moho, view) local mesh = moho:DrawingMesh() if (mesh == nil) then return end if (self.lastSelectedCount ~= moho:CountSelectedPoints()) then self.lastSelectedCount = moho:CountSelectedPoints() self.pivotOffset:Set(0, 0) end if self.isMouseDragging then local g = view:Graphics() g:SelectionRect(self.selRect) return end local g = view:Graphics() local matrix = LM.Matrix:new_local() moho.drawingLayer:GetFullTransform(moho.layerFrame, matrix, moho.document) g:Push() g:ApplyMatrix(matrix) if self.isMousePressed and self.isBezierChanged and self.drawingStatus then g:SetSmoothing(true) g:SetColor(240, 22, 22, 128) g:SetPenWidth(2) g:DrawLine(self.handlePt.x, self.handlePt.y, self.midPt.x, self.midPt.y) g:DrawLine(self.midPt.x, self.midPt.y, self.handlePt2.x, self.handlePt2.y) g:FillCirclePixelRadius(self.handlePt, 3.5) g:FillCirclePixelRadius(self.handlePt2, 3.5) end if not self.dragging and self.selectedPoints > 1 or self.mode == 11 then local min = LM.Vector2:new_local() local max = LM.Vector2:new_local() local matrix = LM.Matrix:new_local() local centerVec = LM.Vector2:new_local() local v = LM.Vector2:new_local() local vc1 = LM.ColorVector:new_local() local vc2 = LM.ColorVector:new_local() vc1:Set(MOHO.MohoGlobals.SelCol) vc2:Set(MOHO.MohoGlobals.BackCol) vc1 = (vc1 + vc2) / 2 local col = vc1:AsColorStruct() local bbox = self:SelectedMeshBounds(moho, moho.drawingLayer, mesh, moho.drawingFrame, view) min:Set(bbox.fMin.x, bbox.fMin.y) max:Set(bbox.fMax.x, bbox.fMax.y) g:SetColor(col) g:SetPenWidth(1) g:SetSmoothing(true) g:DrawLine(min.x, min.y, max.x, min.y) g:DrawLine(min.x, max.y, max.x, max.y) g:DrawLine(min.x, min.y, min.x, max.y) g:DrawLine(max.x, min.y, max.x, max.y) g:SetPenWidth(1) local rotWidth = max.x - min.x if (max.y - min.y > rotWidth) then rotWidth = max.y - min.y end rotWidth = rotWidth * 0.1 g:DrawLine(min.x - rotWidth, min.y - rotWidth, min.x - rotWidth, max.y + rotWidth) g:DrawLine(min.x - rotWidth, max.y + rotWidth, max.x + rotWidth, max.y + rotWidth) g:DrawLine(max.x + rotWidth, max.y + rotWidth, max.x + rotWidth, min.y - rotWidth) g:DrawLine(max.x + rotWidth, min.y - rotWidth, min.x - rotWidth, min.y - rotWidth) g:SetPenWidth(2) v:Set(min.x, min.y) g:FrameCirclePixelRadius(v, self.markerR) v:Set(min.x, max.y) g:FrameCirclePixelRadius(v, self.markerR) v:Set(max.x, min.y) g:FrameCirclePixelRadius(v, self.markerR) v:Set(max.x, max.y) g:FrameCirclePixelRadius(v, self.markerR) v:Set((min.x + max.x) / 2, min.y) g:FrameCirclePixelRadius(v, self.markerR) v:Set((min.x + max.x) / 2, max.y) g:FrameCirclePixelRadius(v, self.markerR) v:Set(min.x, (min.y + max.y) / 2) g:FrameCirclePixelRadius(v, self.markerR) v:Set(max.x, (min.y + max.y) / 2) g:FrameCirclePixelRadius(v, self.markerR) if self.enableSkewTransformation then v:Set((min.x + max.x) / 2, min.y - rotWidth) g:FrameCirclePixelRadius(v, self.markerR + 2) v:Set((min.x + max.x) / 2, max.y + rotWidth) g:FrameCirclePixelRadius(v, self.markerR + 2) v:Set(min.x - rotWidth, (min.y + max.y) / 2) g:FrameCirclePixelRadius(v, self.markerR + 2) v:Set(max.x + rotWidth, (min.y + max.y) / 2) g:FrameCirclePixelRadius(v, self.markerR + 2) end if self.enableDistortTransformation and self.selectedPoints > 2 then v:Set(min.x - rotWidth, min.y - rotWidth) g:FrameCirclePixelRadius(v, self.markerR + 2) v:Set(min.x - rotWidth, max.y + rotWidth) g:FrameCirclePixelRadius(v, self.markerR + 2) v:Set(max.x + rotWidth, min.y - rotWidth) g:FrameCirclePixelRadius(v, self.markerR + 2) v:Set(max.x + rotWidth, max.y + rotWidth) g:FrameCirclePixelRadius(v, self.markerR + 2) end g:SetPenWidth(1) if (self.dragging) then centerVec:Set(self.centerVec) else centerVec = mesh:SelectedCenter() centerVec = centerVec + self.pivotOffset end if self.selectedPoints > 1 then g:SetColor(col) g:SetSmoothing(true) g:DrawLine(centerVec.x - 0.05, centerVec.y, centerVec.x + 0.05, centerVec.y) g:DrawLine(centerVec.x, centerVec.y - 0.05, centerVec.x, centerVec.y + 0.05) v:Set(centerVec.x, centerVec.y) g:FrameCirclePixelRadius(v, self.markerR) end end if self.drawWeldPoint then if (self.endWeldToPoint) then g:SetColor(0, 255, 0, 128) else g:SetColor(255, 0, 0, 128) end g:SetSmoothing(true) g:SetBezierTolerance(2) g:FillCircle(self.endWeldVec, moho:PixelToDoc(self.autoWeldRadius * 0.15) / g:CurrentScale(false)) g:SetSmoothing(false) end if self.selectedPoints == 1 and self.showHandles and (self.dragPoint or not self.drawingStatus ) then local meshLayer = moho:LayerAsVector(moho.drawingLayer) meshLayer:DrawHandles(moho.document, g, not self.showAllHandles) end g:Pop() end -- ************************************************** -- Tool Panel Layout -- ************************************************** local MR_CurveToolSettingsDialog = {} MR_CurveToolSettingsDialog.DRAW_IN_ZERO_FRAME = MOHO.MSG_BASE MR_CurveToolSettingsDialog.DRAW_IN_NON_ZERO_FRAME = MOHO.MSG_BASE + 1 MR_CurveToolSettingsDialog.ALWAYS_DRAW_ON_FBF = MOHO.MSG_BASE + 2 MR_CurveToolSettingsDialog.DRAW_BEHIND = MOHO.MSG_BASE + 3 MR_CurveToolSettingsDialog.USE_PEAK_FOR_CORNERS = MOHO.MSG_BASE + 4 MR_CurveToolSettingsDialog.SHOW_ALL_HANDLES = MOHO.MSG_BASE + 5 MR_CurveToolSettingsDialog.ENABLE_SKEW_TRANSFORMATION = MOHO.MSG_BASE + 6 MR_CurveToolSettingsDialog.ENABLE_DISTORT_TRANSFORMATION = MOHO.MSG_BASE + 7 MR_CurveToolSettingsDialog.CLICK_TO_SELECT = MOHO.MSG_BASE + 8 function MR_CurveToolSettingsDialog:new() local d = LM.GUI.SimpleDialog(MR_CurveTool:Localize('UILabel'), MR_CurveToolSettingsDialog) local l = d:GetLayout() d.drawInZeroFrameCheck = LM.GUI.CheckBox(MR_CurveTool:Localize('Draw in zero frame'), self.DRAW_IN_ZERO_FRAME) l:AddChild(d.drawInZeroFrameCheck, LM.GUI.ALIGN_LEFT, 0) d.drawInNonZeroFrameCheck = LM.GUI.CheckBox(MR_CurveTool:Localize('Draw in non zero frames'), self.DRAW_IN_NON_ZERO_FRAME) l:AddChild(d.drawInNonZeroFrameCheck, LM.GUI.ALIGN_LEFT, 0) d.alwaysDrawOnFBFCheck = LM.GUI.CheckBox(MR_CurveTool:Localize('Always draw on FBF'), self.ALWAYS_DRAW_ON_FBF) l:AddChild(d.alwaysDrawOnFBFCheck, LM.GUI.ALIGN_LEFT, 0) d.drawBehindCheck = LM.GUI.CheckBox(MR_CurveTool:Localize('Draw behind'), self.DRAW_BEHIND) l:AddChild(d.drawBehindCheck, LM.GUI.ALIGN_LEFT, 0) d.usePeakForCornersCheck = LM.GUI.CheckBox(MR_CurveTool:Localize('Use Peak for corners'), self.USE_PEAK_FOR_CORNERS) d.usePeakForCornersCheck:SetToolTip(MR_CurveTool:Localize('Use Peak for corners Tooltip')) l:AddChild(d.usePeakForCornersCheck, LM.GUI.ALIGN_LEFT, 0) l:AddChild(LM.GUI.Divider(false), LM.GUI.ALIGN_FILL) d.showAllHandlesCheck = LM.GUI.CheckBox(MR_CurveTool:Localize('Show all handles'), self.SHOW_ALL_HANDLES) l:AddChild(d.showAllHandlesCheck, LM.GUI.ALIGN_LEFT, 0) d.enableSkewTransformationCheck = LM.GUI.CheckBox(MR_CurveTool:Localize('Enable skew transformation'), self.ENABLE_SKEW_TRANSFORMATION) l:AddChild(d.enableSkewTransformationCheck, LM.GUI.ALIGN_LEFT, 0) d.enableDistortTransformationCheck = LM.GUI.CheckBox(MR_CurveTool:Localize('Enable distort transformation'), self.ENABLE_DISTORT_TRANSFORMATION) l:AddChild(d.enableDistortTransformationCheck, LM.GUI.ALIGN_LEFT, 0) d.clickToSelectCheck = LM.GUI.CheckBox(MR_CurveTool:Localize('Click to select'), self.CLICK_TO_SELECT) l:AddChild(d.clickToSelectCheck, LM.GUI.ALIGN_LEFT, 0) return d end function MR_CurveToolSettingsDialog:UpdateWidgets(moho) self.drawInZeroFrameCheck:SetValue(MR_CurveTool.drawInZeroFrame) self.drawInNonZeroFrameCheck:SetValue(MR_CurveTool.drawInNonZeroFrame) self.alwaysDrawOnFBFCheck:SetValue(MR_CurveTool.alwaysDrawOnFBF) self.drawBehindCheck:SetValue(MR_CurveTool.drawBehind) self.usePeakForCornersCheck:SetValue(MR_CurveTool.usePeakForCorners) self.showAllHandlesCheck:SetValue(MR_CurveTool.showAllHandles) self.enableSkewTransformationCheck:SetValue(MR_CurveTool.enableSkewTransformation) self.enableDistortTransformationCheck:SetValue(MR_CurveTool.enableDistortTransformation) self.clickToSelectCheck:SetValue(MR_CurveTool.clickToSelect) end function MR_CurveToolSettingsDialog:OnOK(moho) MR_CurveTool.drawInZeroFrame = self.drawInZeroFrameCheck:Value() MR_CurveTool.drawInNonZeroFrame = self.drawInNonZeroFrameCheck:Value() MR_CurveTool.alwaysDrawOnFBF = self.alwaysDrawOnFBFCheck:Value() MR_CurveTool.drawBehind = self.drawBehindCheck:Value() MR_CurveTool.usePeakForCorners = self.usePeakForCornersCheck:Value() MR_CurveTool.showAllHandles = self.showAllHandlesCheck:Value() MR_CurveTool.enableSkewTransformation = self.enableSkewTransformationCheck:Value() MR_CurveTool.enableDistortTransformation = self.enableDistortTransformationCheck:Value() MR_CurveTool.clickToSelect = self.clickToSelectCheck:Value() end function MR_CurveToolSettingsDialog:HandleMessage(msg) if msg == self.DRAW_IN_ZERO_FRAME then MR_CurveTool.drawInZeroFrame = self.drawInZeroFrameCheck:Value() elseif msg == self.DRAW_IN_NON_ZERO_FRAME then MR_CurveTool.drawInNonZeroFrame = self.drawInNonZeroFrameCheck:Value() elseif msg == self.ALWAYS_DRAW_ON_FBF then MR_CurveTool.alwaysDrawOnFBF = self.alwaysDrawOnFBFCheck:Value() elseif msg == self.DRAW_BEHIND then MR_CurveTool.drawBehind = self.drawBehindCheck:Value() elseif msg == self.USE_PEAK_FOR_CORNERS then MR_CurveTool.usePeakForCorners = self.usePeakForCornersCheck:Value() elseif msg == self.SHOW_ALL_HANDLES then MR_CurveTool.showAllHandles = self.showAllHandlesCheck:Value() if MR_CurveTool.mohoVersion > 13 then local helper = MOHO.ScriptInterfaceHelper:new_local() local moho = helper:MohoObject() moho.view:DrawMe() helper:delete() end elseif msg == self.ENABLE_SKEW_TRANSFORMATION then MR_CurveTool.enableSkewTransformation = self.enableSkewTransformationCheck:Value() elseif msg == self.ENABLE_DISTORT_TRANSFORMATION then MR_CurveTool.enableDistortTransformation = self.enableDistortTransformationCheck:Value() elseif msg == self.CLICK_TO_SELECT then MR_CurveTool.clickToSelect = self.clickToSelectCheck:Value() end end MR_CurveTool.SINGLE_CURVE_MODE = MOHO.MSG_BASE MR_CurveTool.POINTS = MOHO.MSG_BASE + 1 MR_CurveTool.CURVATURE = MOHO.MSG_BASE + 2 MR_CurveTool.CURVATURE_SC = MOHO.MSG_BASE + 3 MR_CurveTool.SHOW_HANDLES = MOHO.MSG_BASE + 4 MR_CurveTool.FIXED_HANDLES = MOHO.MSG_BASE + 5 MR_CurveTool.USE_BEZIER_HANDLES = MOHO.MSG_BASE + 6 MR_CurveTool.THRESHOLD = MOHO.MSG_BASE + 7 MR_CurveTool.AUTOWELD = MOHO.MSG_BASE + 8 MR_CurveTool.SHARP_CORNERS = MOHO.MSG_BASE + 9 MR_CurveTool.AUTO_FILL = MOHO.MSG_BASE + 10 MR_CurveTool.FILLCOLOR = MOHO.MSG_BASE + 11 MR_CurveTool.AUTO_LINE = MOHO.MSG_BASE + 12 MR_CurveTool.LINECOLOR = MOHO.MSG_BASE + 13 MR_CurveTool.LINEWIDTH = MOHO.MSG_BASE + 14 MR_CurveTool.PIVOT_UP_LEFT = MOHO.MSG_BASE + 15 MR_CurveTool.PIVOT_MID_LEFT = MOHO.MSG_BASE + 16 MR_CurveTool.PIVOT_DOWN_LEFT = MOHO.MSG_BASE + 17 MR_CurveTool.PIVOT_UP_MID = MOHO.MSG_BASE + 18 MR_CurveTool.PIVOT_CENTER = MOHO.MSG_BASE + 19 MR_CurveTool.PIVOT_DOWN_MID = MOHO.MSG_BASE + 20 MR_CurveTool.PIVOT_UP_RIGHT = MOHO.MSG_BASE + 21 MR_CurveTool.PIVOT_MID_RIGHT = MOHO.MSG_BASE + 22 MR_CurveTool.PIVOT_DOWN_RIGHT = MOHO.MSG_BASE + 23 function MR_CurveTool:DoLayout(moho, layout) self.dlog = MR_CurveToolSettingsDialog:new() self.settingsPopup = LM.GUI.PopupDialog(self:Localize('Settings'), false, 0) self.settingsPopup:SetDialog(self.dlog) layout:AddChild(self.settingsPopup, LM.GUI.ALIGN_LEFT, 0) layout:AddChild(LM.GUI.Divider(true), LM.GUI.ALIGN_FILL) if self.singleCurveMode then self.singleCurveModeImageButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_single_curve_mode', self:Localize('Single curve mode'), true, self.SINGLE_CURVE_MODE, false) layout:AddChild(self.singleCurveModeImageButton, LM.GUI.ALIGN_LEFT, 0) else self.singleCurveModeImageButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_curve_mode', self:Localize('Curve mode'), true, self.SINGLE_CURVE_MODE, false) layout:AddChild(self.singleCurveModeImageButton, LM.GUI.ALIGN_LEFT, 0) end layout:AddChild(LM.GUI.Divider(true), LM.GUI.ALIGN_FILL) if self.singleCurveMode then self.curvatureSCInput = LM.GUI.TextControl(50, '0.3', self.CURVATURE_SC, LM.GUI.FIELD_FLOAT, self:Localize('Curvature')) self.curvatureSCInput:SetWheelInc(0.05) layout:AddChild(self.curvatureSCInput, LM.GUI.ALIGN_LEFT, 0) self.curvatureInput = nil else self.curvatureInput = LM.GUI.TextControl(50, '0.3', self.CURVATURE, LM.GUI.FIELD_FLOAT, self:Localize('Curvature')) self.curvatureInput:SetWheelInc(0.05) layout:AddChild(self.curvatureInput, LM.GUI.ALIGN_LEFT, 0) self.curvatureSCInput = nil end self.showHandlesButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_show_handles', self:Localize('Show handles tooltip'), true, self.SHOW_HANDLES, false) layout:AddChild(self.showHandlesButton, LM.GUI.ALIGN_LEFT, 0) self.fixedHandlesImageButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_fixed_handles', self:Localize('Fixed handles tooltip'), true, self.FIXED_HANDLES, false) layout:AddChild(self.fixedHandlesImageButton, LM.GUI.ALIGN_LEFT, 0) layout:AddChild(LM.GUI.Divider(true), LM.GUI.ALIGN_FILL) if self.singleCurveMode then self.pointsInput = LM.GUI.TextControl(0, '100', self.POINTS, LM.GUI.FIELD_INT, self:Localize('Points')) layout:AddChild(self.pointsInput, LM.GUI.ALIGN_LEFT, 0) else self.useBezierHandlesCheck = LM.GUI.CheckBox(self:Localize('Bezier drawing mode'), self.USE_BEZIER_HANDLES) layout:AddChild(self.useBezierHandlesCheck) self.thresholdInput = LM.GUI.TextControl(50, '0.3', self.THRESHOLD, LM.GUI.FIELD_FLOAT, self:Localize('Threshold')) self.thresholdInput:SetWheelInc(0.01) layout:AddChild(self.thresholdInput, LM.GUI.ALIGN_LEFT, 0) end layout:AddChild(LM.GUI.Divider(true), LM.GUI.ALIGN_FILL) self.autoWeldCheck = LM.GUI.CheckBox(self:Localize('Auto-weld'), self.AUTOWELD) layout:AddChild(self.autoWeldCheck) if not self.singleCurveMode then self.sharpCornersCheck = LM.GUI.CheckBox(self:Localize('Sharp corners'), self.SHARP_CORNERS) layout:AddChild(self.sharpCornersCheck) end self.fillCheck = LM.GUI.CheckBox(self:Localize('Auto-fill:'), self.AUTO_FILL) layout:AddChild(self.fillCheck) self.fillCol = LM.GUI.ShortColorSwatch(true, self.FILLCOLOR) layout:AddChild(self.fillCol) self.lineCheck = LM.GUI.CheckBox(self:Localize('Auto-stroke:'), self.AUTO_LINE) layout:AddChild(self.lineCheck) self.lineCol = LM.GUI.ShortColorSwatch(true, self.LINECOLOR) layout:AddChild(self.lineCol) layout:AddChild(LM.GUI.StaticText(self:Localize('Width:'))) self.lineWidth = LM.GUI.TextControl(0, "00.0000", self.LINEWIDTH, LM.GUI.FIELD_UFLOAT) self.lineWidth:SetWheelInc(1.0) self.lineWidth:SetWheelInteger(true) layout:AddChild(self.lineWidth) layout:AddChild(LM.GUI.Divider(true), LM.GUI.ALIGN_FILL) layout:PushV() self.pivotLUButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_small_button', self:Localize('Set pivot to left up corner'), false, self.PIVOT_UP_LEFT, false) layout:AddChild(self.pivotLUButton, LM.GUI.ALIGN_LEFT, 0) layout:AddPadding(-14) self.pivotLMButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_small_button', self:Localize('Set pivot to left'), false, self.PIVOT_MID_LEFT, false) layout:AddChild(self.pivotLMButton, LM.GUI.ALIGN_LEFT, 0) layout:AddPadding(-14) self.pivotLDButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_small_button', self:Localize('Set pivot to left down corner'), false, self.PIVOT_DOWN_LEFT, false) layout:AddChild(self.pivotLDButton, LM.GUI.ALIGN_LEFT, 0) layout:Pop() layout:AddPadding(-14) layout:PushV() self.pivotMUButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_small_button', self:Localize('Set pivot to up'), false, self.PIVOT_UP_MID, false) layout:AddChild(self.pivotMUButton, LM.GUI.ALIGN_LEFT, 0) layout:AddPadding(-14) self.pivotCButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_small_button', self:Localize('Set pivot to center'), false, self.PIVOT_CENTER, false) layout:AddChild(self.pivotCButton, LM.GUI.ALIGN_LEFT, 0) layout:AddPadding(-14) self.pivotMUButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_small_button', self:Localize('Set pivot to down'), false, self.PIVOT_DOWN_MID, false) layout:AddChild(self.pivotMUButton, LM.GUI.ALIGN_LEFT, 0) layout:Pop() layout:AddPadding(-14) layout:PushV() self.pivotRUButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_small_button', self:Localize('Set pivot to right up corner'), false, self.PIVOT_UP_RIGHT, false) layout:AddChild(self.pivotRUButton, LM.GUI.ALIGN_LEFT, 0) layout:AddPadding(-14) self.pivotRMButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_small_button', self:Localize('Set pivot to right'), false, self.PIVOT_MID_RIGHT, false) layout:AddChild(self.pivotRMButton, LM.GUI.ALIGN_LEFT, 0) layout:AddPadding(-14) self.pivotRDButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_small_button', self:Localize('Set pivot to right down corner'), false, self.PIVOT_DOWN_RIGHT, false) layout:AddChild(self.pivotRDButton, LM.GUI.ALIGN_LEFT, 0) layout:Pop() layout:AddChild(LM.GUI.StaticText('v'..MR_CurveTool:Version())) end function MR_CurveTool:UpdateWidgets(moho) if self.reset then self.reset = false local frame = moho.frame if frame == 0 then moho:SetCurFrame(1) moho:SetCurFrame(0) elseif frame ~= 0 then moho:SetCurFrame(0) moho:SetCurFrame(frame) end end if self.skewCursor == nil then self.skewCursor = LM.GUI.Cursor("ScriptResources/mr_curve_tool/mr_cursor_skew", 1, 1) end if self.distortCursor == nil then self.distortCursor = LM.GUI.Cursor("ScriptResources/mr_curve_tool/mr_cursor_distort", 1, 1) end local mesh = moho:DrawingMesh() if (mesh == nil) then return end self.singleCurveModeImageButton:SetValue(self.singleCurveMode) self.showHandlesButton:SetValue(self.showHandles) self.fixedHandlesImageButton:SetValue(self.fixedHandles) if self.curvatureInput ~= nil then self.curvatureInput:SetValue(self.curvature) self.useBezierHandlesCheck:SetValue(self.useBezierHandles) self.thresholdInput:SetValue(self.threshold) self.thresholdInput:Enable(self.useBezierHandles) self.sharpCornersCheck:SetValue(self.sharpCorners) end if self.curvatureSCInput ~= nil then self.curvatureSCInput:SetValue(self.curvatureSC) self.pointsInput:SetValue(self.points) end self.autoWeldCheck:SetValue(self.autoWeld) self.fillCheck:SetValue(self.autoFill) self.lineCheck:SetValue(self.autoStroke) if moho.drawingLayer:CurrentAction() ~= "" then self.curvatureInput:Enable(false) self.useBezierHandlesCheck:Enable(false) self.thresholdInput:Enable(false) self.autoWeldCheck:Enable(false) self.sharpCornersCheck:Enable(false) self.fillCheck:Enable(false) self.lineCheck:Enable(false) self.lineWidth:Enable(false) end local style = moho:CurrentEditStyle() if (style ~= nil) then self.fillCol:SetValue(style.fFillCol.value) self.lineCol:SetValue(style.fLineCol.value) self.lineWidth:SetValue(style.fLineWidth * moho.document:Height()) else local fillColor = LM.rgb_color:new_local() fillColor.r = self.fillColorR fillColor.g = self.fillColorG fillColor.b = self.fillColorB fillColor.a = self.fillColorA local strokeColor = LM.rgb_color:new_local() strokeColor.r = self.strokeColorR strokeColor.g = self.strokeColorG strokeColor.b = self.strokeColorB strokeColor.a = self.strokeColorA self.fillCol:SetValue(fillColor) self.lineCol:SetValue(strokeColor) self.lineWidth:SetValue(self.strokeWidth) end end function MR_CurveTool:HandleMessage(moho, view, msg) local mesh = moho:DrawingMesh() if (mesh == nil) then return end local style = moho:CurrentEditStyle() if msg == self.SINGLE_CURVE_MODE then self.singleCurveMode = self.singleCurveModeImageButton:Value() local drawingToolsNonZero = MOHO.MohoGlobals.DisableDrawingToolsNonZero if not drawingToolsNonZero then MOHO.MohoGlobals.DisableDrawingToolsNonZero = true end local frame = moho.frame if frame == 0 then moho:SetCurFrame(1) moho:SetCurFrame(0) elseif frame ~= 0 then moho:SetCurFrame(0) moho:SetCurFrame(frame) end if not drawingToolsNonZero then MOHO.MohoGlobals.DisableDrawingToolsNonZero = drawingToolsNonZero end elseif msg == self.POINTS then self.points = LM.Clamp(self.pointsInput:Value(), 1, 100) self.pointsInput:SetValue(self.points) elseif msg == self.CURVATURE then self.curvature = LM.Clamp(self.curvatureInput:Value(), MOHO.PEAKED + self.peakedCorner, 1) self.curvatureInput:SetValue(self.curvature) elseif msg == self.CURVATURE_SC then self.curvatureSC = LM.Clamp(self.curvatureSCInput:Value(), 0, 1) self.curvatureSCInput:SetValue(self.curvatureSC) elseif msg == self.SHOW_HANDLES then self.showHandles = self.showHandlesButton:Value() elseif msg == self.FIXED_HANDLES then self.fixedHandles = self.fixedHandlesImageButton:Value() elseif msg == self.USE_BEZIER_HANDLES then self.useBezierHandles = self.useBezierHandlesCheck:Value() self.thresholdInput:Enable(self.useBezierHandles) elseif msg == self.THRESHOLD then self.threshold = LM.Clamp(self.thresholdInput:Value(), 0.01, 0.3) self.thresholdInput:SetValue(self.threshold) elseif msg == self.AUTOWELD then self.autoWeld = self.autoWeldCheck:Value() elseif msg == self.SHARP_CORNERS then self.sharpCorners = self.sharpCornersCheck:Value() elseif msg == self.AUTO_FILL then self.autoFill = self.fillCheck:Value() moho:UpdateUI() elseif msg == self.FILLCOLOR then if (style ~= nil) then style.fFillCol:SetValue(moho.layerFrame, self.fillCol:Value()) end local fillColor = self.fillCol:Value() self.fillColorR = fillColor.r self.fillColorG = fillColor.g self.fillColorB = fillColor.b self.fillColorA = fillColor.a moho:UpdateUI() elseif msg == self.AUTO_LINE then self.autoStroke = self.lineCheck:Value() moho:UpdateUI() elseif msg == self.LINECOLOR then if (style ~= nil) then style.fLineCol:SetValue(moho.layerFrame, self.lineCol:Value()) end local strokeColor = self.lineCol:Value() self.strokeColorR = strokeColor.r self.strokeColorG = strokeColor.g self.strokeColorB = strokeColor.b self.strokeColorA = strokeColor.a moho:UpdateUI() elseif (msg == self.LINEWIDTH) then local lineWidth = self.lineWidth:FloatValue() lineWidth = LM.Clamp(lineWidth, 0.25, 256) if (style ~= nil) then style.fLineWidth = lineWidth / moho.document:Height() end self.strokeWidth = lineWidth moho:UpdateUI() elseif (msg == self.PIVOT_UP_LEFT) then self.selectedMin = LM.Vector2:new_local() self.selectedMax = LM.Vector2:new_local() mesh:SelectedBounds(self.selectedMin, self.selectedMax) local centerVec = LM.Vector2:new_local() centerVec:Set(self.selectedMax.x, self.selectedMin.y) self.centerVec = mesh:SelectedCenter() self.pivotOffset = self.centerVec - centerVec self.centerVec = self.centerVec + self.pivotOffset elseif (msg == self.PIVOT_MID_LEFT) then self.selectedMin = LM.Vector2:new_local() self.selectedMax = LM.Vector2:new_local() mesh:SelectedBounds(self.selectedMin, self.selectedMax) local centerVec = LM.Vector2:new_local() centerVec:Set(self.selectedMax.x, (self.selectedMin.y + self.selectedMax.y) / 2.0) self.centerVec = mesh:SelectedCenter() self.pivotOffset = self.centerVec - centerVec self.centerVec = self.centerVec + self.pivotOffset elseif (msg == self.PIVOT_DOWN_LEFT) then self.selectedMin = LM.Vector2:new_local() self.selectedMax = LM.Vector2:new_local() mesh:SelectedBounds(self.selectedMin, self.selectedMax) local centerVec = LM.Vector2:new_local() centerVec:Set(self.selectedMax.x, self.selectedMax.y) self.centerVec = mesh:SelectedCenter() self.pivotOffset = self.centerVec - centerVec self.centerVec = self.centerVec + self.pivotOffset elseif (msg == self.PIVOT_UP_MID) then self.selectedMin = LM.Vector2:new_local() self.selectedMax = LM.Vector2:new_local() mesh:SelectedBounds(self.selectedMin, self.selectedMax) local centerVec = LM.Vector2:new_local() centerVec:Set((self.selectedMin.x + self.selectedMax.x) / 2.0, self.selectedMin.y) self.centerVec = mesh:SelectedCenter() self.pivotOffset = self.centerVec - centerVec self.centerVec = self.centerVec + self.pivotOffset elseif (msg == self.PIVOT_CENTER) then self.selectedMin = LM.Vector2:new_local() self.selectedMax = LM.Vector2:new_local() mesh:SelectedBounds(self.selectedMin, self.selectedMax) local centerVec = LM.Vector2:new_local() centerVec:Set((self.selectedMin.x + self.selectedMax.x) / 2.0, (self.selectedMin.y + self.selectedMax.y) / 2.0) self.centerVec = mesh:SelectedCenter() self.pivotOffset = self.centerVec - centerVec self.centerVec = self.centerVec + self.pivotOffset elseif (msg == self.PIVOT_DOWN_MID) then self.selectedMin = LM.Vector2:new_local() self.selectedMax = LM.Vector2:new_local() mesh:SelectedBounds(self.selectedMin, self.selectedMax) local centerVec = LM.Vector2:new_local() centerVec:Set((self.selectedMin.x + self.selectedMax.x) / 2.0, self.selectedMax.y) self.centerVec = mesh:SelectedCenter() self.pivotOffset = self.centerVec - centerVec self.centerVec = self.centerVec + self.pivotOffset elseif (msg == self.PIVOT_UP_RIGHT) then self.selectedMin = LM.Vector2:new_local() self.selectedMax = LM.Vector2:new_local() mesh:SelectedBounds(self.selectedMin, self.selectedMax) local centerVec = LM.Vector2:new_local() centerVec:Set(self.selectedMin.x, self.selectedMin.y) self.centerVec = mesh:SelectedCenter() self.pivotOffset = self.centerVec - centerVec self.centerVec = self.centerVec + self.pivotOffset elseif (msg == self.PIVOT_MID_RIGHT) then self.selectedMin = LM.Vector2:new_local() self.selectedMax = LM.Vector2:new_local() mesh:SelectedBounds(self.selectedMin, self.selectedMax) local centerVec = LM.Vector2:new_local() centerVec:Set(self.selectedMin.x, (self.selectedMin.y + self.selectedMax.y) / 2.0) self.centerVec = mesh:SelectedCenter() self.pivotOffset = self.centerVec - centerVec self.centerVec = self.centerVec + self.pivotOffset elseif (msg == self.PIVOT_DOWN_RIGHT) then self.selectedMin = LM.Vector2:new_local() self.selectedMax = LM.Vector2:new_local() mesh:SelectedBounds(self.selectedMin, self.selectedMax) local centerVec = LM.Vector2:new_local() centerVec:Set(self.selectedMin.x, self.selectedMax.y) self.centerVec = mesh:SelectedCenter() self.pivotOffset = self.centerVec - centerVec self.centerVec = self.centerVec + self.pivotOffset end end function MR_CurveTool:GetColosestVec(moho, view, vec1, vec2) local testVec1 = LM.Vector2:new_local() testVec1:Set(vec1) local testVec2 = LM.Vector2:new_local() testVec2:Set(vec2) local p1 = LM.Point:new_local() local p2 = LM.Point:new_local() local m = LM.Matrix:new_local() moho.drawingLayer:GetFullTransform(moho.layerFrame, m, moho.document) m:Transform(testVec1) m:Transform(testVec2) view:Graphics():WorldToScreen(testVec1, p1) view:Graphics():WorldToScreen(testVec2, p2) p1.x = p1.x - p2.x p1.y = p1.y - p2.y local closest = (p1.x * p1.x) + (p1.y * p1.y) return closest end function MR_CurveTool:AddPointOnCurve(moho, mouseEvent) local mesh = moho:DrawingMesh() if (mesh == nil) then return end local sharpCorners = false if (mouseEvent.ctrlKey and not self.sharpCorners) or (not mouseEvent.ctrlKey and self.sharpCorners) then sharpCorners = true end local curveID = -1 local segID = -1 local newPoint if (not mouseEvent.altKey and self.autoWeld) or (mouseEvent.altKey and not self.autoWeld) then local pickWidth = 5 curveID = -1 segID = -1 curveID, segID = mouseEvent.view:PickEdge(mouseEvent.pt, curveID, segID, pickWidth) end if segID >= 0 then if (curveID >= 0) then -- add a point in the middle of some curve local v = mesh:Curve(curveID):ClosestPointOnSegment(segID, mouseEvent.drawingVec, true, true) mesh:AddPoint(v, curveID, segID, moho.layerFrame, self.fixedHandles, true) newPoint = mesh:Point(mesh:CountPoints() - 1) else -- add a new curve segment mesh:AddPoint(mouseEvent.drawingVec, -1, moho.layerFrame) if (sharpCorners) then mesh:Point(mesh:CountPoints() - 1):SetCurvature(MOHO.PEAKED + self.peakedCorner, moho.layerFrame) mesh:Point(mesh:CountPoints() - 2):SetCurvature(MOHO.PEAKED + self.peakedCorner, moho.layerFrame) end self.secondPtID = mesh:CountPoints() - 2 newPoint = mesh:Point(self.secondPtID) end if (sharpCorners) then mesh:Point(mesh:CountPoints() - 1):SetCurvature(MOHO.PEAKED + self.peakedCorner, moho.layerFrame) end end return newPoint end function MR_CurveTool:CleaUpAllPoints(moho) local mesh = moho:DrawingMesh() if (mesh == nil) then return end if (moho.layerFrame > 0) then for i=0, mesh:CountPoints()-1 do self:ClearPointKeys(moho, i) end end end function MR_CurveTool:ClearPointKeys(moho, ptID) local mesh = moho:DrawingMesh() if mesh == nil or not ptID then return end if (moho.layerFrame > 0) then if (ptID >= 0 and ptID < mesh:CountPoints()) then local point = mesh:Point(ptID) point.fAnimPos:SetValue(0, point.fAnimPos.value) point.fAnimPos:DeleteKey(moho.layerFrame) point.fWidth:SetValue(0, 1) point.fWidth:DeleteKey(moho.layerFrame) point.fColor:SetValue(0, point.fColor.value) point.fColor:DeleteKey(moho.layerFrame) point.fColorStrength:SetValue(0, point.fColorStrength.value) point.fColorStrength:DeleteKey(moho.layerFrame) for i = 0, point:CountCurves() - 1 do local curve = nil local ptPos = -1 curve, ptPos = point:Curve(i, ptPos) if curve ~= nil then curve:SetCurvature(ptPos, curve:GetCurvature(ptPos, moho.layerFrame), 0) curve:SetWeight(ptPos, curve:GetWeight(ptPos, moho.layerFrame, true), 0, true) curve:SetWeight(ptPos, curve:GetWeight(ptPos, moho.layerFrame, false), 0, false) curve:SetOffset(ptPos, curve:GetOffset(ptPos, moho.layerFrame, true), 0, true) curve:SetOffset(ptPos, curve:GetOffset(ptPos, moho.layerFrame, false), 0, false) if self.isMoho13_5_3 then curve:DeleteCurvatureKey(ptPos, moho.layerFrame) end end end end end end function MR_CurveTool:IsPointEdge(moho, mesh, point, endPoint) if point:IsEndpoint() and endPoint then return false end local edgePointsList = self:CollectEdgePoints(moho, mesh, point) if #edgePointsList > 0 then return true else return false end end function MR_CurveTool:ArePointsConnected(moho, mesh, point1, point2) for i=0, point1:CountCurves()-1 do local curve = point1:Curve(i, -1) local curveID = mesh:CurveID(curve) if point2:IsPointOnCurve(curveID) then return true end end return false end function MR_CurveTool:FindFirstEdgePointID(moho, mesh, point) if point:IsEndpoint() then return -1 end local pointID = -1 for i=0, point:CountCurves()-1 do local pointsList = {} pointsList.curvePointID = {} local curve = point:Curve(i, -1) local isCurveEdge = false local direction = true local curveLength = curve:CountPoints() for p=0, curveLength-1 do local curvePoint = curve:Point(p) local pointID = -1 if curvePoint == point then if p == 0 then direction = true isCurveEdge = true pointID = 0 elseif p == curveLength-1 then direction = false isCurveEdge = true pointID = p end if pointID >= 0 then return pointID end end end end return -1 end function MR_CurveTool:CollectEdgePoints(moho, mesh, point) local curvesList = {} curvesList.curve = {} curvesList.meshCurveID = {} curvesList.direction = {} for i=0, point:CountCurves()-1 do local pointsList = {} pointsList.curvePointID = {} local curve = point:Curve(i, -1) local isCurveEdge = false local direction = true local curveLength = curve:CountPoints() if not curve.fClosed then for p=0, curveLength-1 do local curvePoint = curve:Point(p) local pointID = -1 if curvePoint == point then if p == 0 then direction = true isCurveEdge = true pointID = 0 elseif p == curveLength-1 then direction = false isCurveEdge = true pointID = p end if pointID >= 0 then table.insert(pointsList.curvePointID, pointID) end end end if isCurveEdge then table.insert(curvesList, pointsList) table.insert(curvesList.curve, i) table.insert(curvesList.meshCurveID, mesh:CurveID(curve)) table.insert(curvesList.direction, direction) end end end return curvesList end function MR_CurveTool:CreateShape(moho, mesh, curve, filled) mesh:SelectNone() if curve == nil then return end curve:SelectCurvePoints() local style = moho:CurrentEditStyle() moho.view:DrawMe() local shapeID = moho:CreateShape(filled, false, 0) if (shapeID >= 0) then local shape = mesh:Shape(shapeID) shape.fSelected = true if (shape.fFillAllowed) then shape.fHasFill = self.autoFill if not style then local fillColor = LM.rgb_color:new_local() fillColor.r = self.fillColorR fillColor.g = self.fillColorG fillColor.b = self.fillColorB fillColor.a = self.fillColorA shape.fMyStyle.fFillCol:SetValue(0, fillColor) end end shape.fHasOutline = self.autoStroke if not style then local strokeColor = LM.rgb_color:new_local() strokeColor.r = self.strokeColorR strokeColor.g = self.strokeColorG strokeColor.b = self.strokeColorB strokeColor.a = self.strokeColorA shape.fMyStyle.fLineWidth = self.strokeWidth / moho.document:Height() shape.fMyStyle.fLineCol:SetValue(0, strokeColor) end if self.drawBehind then mesh:LowerShape(shapeID, true) shapeID = 0 end moho:UpdateSelectedChannels() end mesh:SelectNone() return shapeID end function MR_CurveTool:CloseCurve(moho, point) local mesh = moho:DrawingMesh() if (mesh == nil) then return end self.drawingStatus = false self.drawWeldPoint = false self.startPoint = -1 local lastPointID = mesh:CountPoints() -1 if lastPointID >= 1 then local point = mesh:Point(lastPointID) point.fAnimPos:SetValue(moho.layerFrame, point.fPos) end self:ClearPointKeys(moho, self.selectedPointID) self:ClearPointKeys(moho, self.lastSelectedPointID) self:ClearPointKeys(moho, self.lastPointID) if self.autoStroke and point then local curve, where = point:Curve(point:CountCurves()-1, -1) local shapeID = self:CreateShape(moho, mesh, curve, false) end self.selectedPointID = -1 mesh:SelectNone() moho.view:DrawMe() moho:UpdateUI() self.isCurveEnded = true end function MR_CurveTool:FindLastCurvePoint(moho, point) local where = -1 local curve, where = point:Curve(point:CountCurves()-1, where) local curvePointID = curve:PointID(point) for i=0, curve:CountPoints()-1 do local curvePoint = curve:Point(i) if curvePoint == point and i > curvePointID then curvePointID = i end end return curvePointID end function MR_CurveTool:TestForClosestHandle(moho, mouseEvent) self.selID = -1 self.handleSide = 0 local mesh = moho:DrawingMesh() if (mesh == nil) then return end local g = mouseEvent.view:Graphics() local layerMatrix = LM.Matrix:new_local() moho.drawingLayer:GetFullTransform(moho.layerFrame, layerMatrix, moho.document) g:Push() g:ApplyMatrix(layerMatrix) self.handleCurveID = 0 local minDistance = 30 local markerR = 6 local pt = LM.Point:new_local() if self.showHandles then for i = 0, mesh:CountCurves() - 1 do local curve = mesh:Curve(i) for j = 0, curve:CountPoints() - 1 do if (not curve:Point(j).fHidden and ((curve:Point(j).fSelected and not self.showAllHandles) or self.showAllHandles)) then if (math.abs(curve:GetCurvature(j, moho.layerFrame)) > MOHO.PEAKED + 0.00001) then local testHandle = curve:GetControlHandle(j, moho.layerFrame, true) mouseEvent.view:Graphics():WorldToScreen(testHandle, pt) if (not(j == 0 and not curve.fClosed)) then local distance = math.sqrt((pt.x - mouseEvent.pt.x) * (pt.x - mouseEvent.pt.x) + (pt.y - mouseEvent.pt.y) * (pt.y - mouseEvent.pt.y)) if (distance < minDistance) then minDistance = distance self.selID = mesh:PointID(curve:Point(j)) self.startHandle = testHandle self.handleSide = -1 self.handleCurveID = i self.handlePointID = j end end testHandle = curve:GetControlHandle(j, moho.layerFrame, false) mouseEvent.view:Graphics():WorldToScreen(testHandle, pt) if (not(j == curve:CountPoints() - 1 and not curve.fClosed)) then local distance = math.sqrt((pt.x - mouseEvent.pt.x) * (pt.x - mouseEvent.pt.x) + (pt.y - mouseEvent.pt.y) * (pt.y - mouseEvent.pt.y)) if (distance < minDistance) then minDistance = distance self.selID = mesh:PointID(curve:Point(j)) self.startHandle = testHandle self.handleSide = 1 self.handleCurveID = i self.handlePointID = j end end end end end end end local ptID = mesh:ClosestPoint(mouseEvent.startVec) if (ptID >= 0) then local selPt = mesh:Point(ptID) mouseEvent.view:Graphics():WorldToScreen(selPt.fPos, pt) local distance = math.sqrt((pt.x - mouseEvent.pt.x) * (pt.x - mouseEvent.pt.x) + (pt.y - mouseEvent.pt.y) * (pt.y - mouseEvent.pt.y)) if (distance < minDistance) then minDistance = distance self.selID = ptID self.handleSide = 0 end end if self.selID >= 0 then mesh:SelectNone() mesh:Point(self.selID).fSelected = true end -- This code is copied from Alexandra Evseeva's scripts. if not self.handlePointID then g:Pop() return end if self.showHandles and self.handleSide ~= 0 then local keyValue = AE_Utilities:GetBezierValue(mesh:Curve(self.handleCurveID), self.handlePointID, moho.layerFrame, (self.handleSide == -1)) self.delta = self.startHandle - keyValue self.correctionMode = true local pointDelta = mesh:Curve(self.handleCurveID):Point(self.handlePointID).fPos - mesh:Curve(self.handleCurveID):Point(self.handlePointID).fAnimPos:GetValue(moho.layerFrame) self.pointDelta = pointDelta local keyLength local resultLength local pp = self.handlePointID + self.handleSide if mesh:Curve(self.handleCurveID).fClosed then if pp < 0 then pp = mesh:Curve(self.handleCurveID):CountPoints()-1 end if pp >= mesh:Curve(self.handleCurveID):CountPoints() then pp = 0 end else if pp < 0 then pp = 0 end if pp >= mesh:Curve(self.handleCurveID):CountPoints() then pp = mesh:Curve(self.handleCurveID):CountPoints()-1 end end if(pp == self.handlePointID) then self.lengthMultiply = 1 keyLength = 0.00001 resultLength = 0.00001 else keyLength = (mesh:Curve(self.handleCurveID):Point(pp).fAnimPos:GetValue(moho.layerFrame) - mesh:Curve(self.handleCurveID):Point(self.handlePointID).fAnimPos:GetValue(moho.layerFrame)):Mag() resultLength = (mesh:Curve(self.handleCurveID):Point(pp).fPos - mesh:Curve(self.handleCurveID):Point(self.handlePointID).fPos):Mag() self.lengthMultiply = resultLength/keyLength end self.startWeight = mesh:Curve(self.handleCurveID):GetWeight(self.handlePointID, moho.layerFrame, (self.handleSide == -1)) self.startOffset = mesh:Curve(self.handleCurveID):GetOffset(self.handlePointID, moho.layerFrame, (self.handleSide == -1)) self.startFPos = mesh:Curve(self.handleCurveID):Point(self.handlePointID).fPos self.startVector = self.startHandle - self.startFPos self.startVectorMag = self.startVector:Mag() local channelNumberBase = 0 for p=0, mesh:PointID(mesh:Curve(self.handleCurveID):Point(self.handlePointID))-1 do local nextPoint = mesh:Point(p) channelNumberBase = channelNumberBase + nextPoint:CountCurves() * 5 end local curvatureChannel = moho.drawingLayer:Channel(3,channelNumberBase, moho.document) local weightChannel = moho:ChannelAsAnimVal(moho.drawingLayer:Channel(3,channelNumberBase+1+self.handleSide/2+0.5, moho.document)) local curvatureDelta = AE_Utilities:SumActionInfluences(moho, moho.layerFrame, moho:ChannelAsAnimVal(curvatureChannel), moho.drawingLayer) local weightDelta = weightChannel.value - weightChannel:GetValue(moho.layerFrame) self.weightDelta = weightDelta self.weightMultiplier = resultLength * (mesh:Curve(self.handleCurveID):GetCurvature(self.handlePointID, moho.layerFrame) + curvatureDelta) end g:Pop() end function MR_CurveTool:SelectedMeshBounds(moho, layer, mesh, frame, view) local bbox = LM.BBox:new_local() local min = LM.Vector2:new_local() local max = LM.Vector2:new_local() mesh:SelectedBounds(min, max) bbox.fMin:Set(min.x, min.y, 0) bbox.fMax:Set(max.x, max.y, 0) -- make sure the bounding box is not too thin in one direction local xLen = bbox.fMax.x - bbox.fMin.x local yLen = bbox.fMax.y - bbox.fMin.y if (xLen < yLen / 10.0) then local center = (bbox.fMin.x + bbox.fMax.x) / 2.0 bbox.fMin.x = center - yLen / 10.0 bbox.fMax.x = center + yLen / 10.0 elseif (yLen < xLen / 10.0) then local center = (bbox.fMin.y + bbox.fMax.y) / 2.0 bbox.fMin.y = center - xLen / 10.0 bbox.fMax.y = center + xLen / 10.0 end -- make sure the bounding box is not too small local minLength = 150 local m = LM.Matrix:new_local() local v = LM.Vector2:new_local() local pt1 = LM.Point:new_local() local pt2 = LM.Point:new_local() layer:GetFullTransform(frame, m, moho.document) v:Set(bbox.fMin.x, bbox.fMin.y) m:Transform(v) view:Graphics():WorldToScreen(v, pt1) v:Set(bbox.fMax.x, bbox.fMax.y) m:Transform(v) view:Graphics():WorldToScreen(v, pt2) pt1 = pt2 - pt1 local length = math.sqrt(pt1.x * pt1.x + pt1.y * pt1.y) if (length < minLength) then center = (bbox.fMin + bbox.fMax) / 2.0 v = bbox.fMax - center bbox.fMax = center + v * (minLength / length) / 2.0 v = bbox.fMin - center bbox.fMin = center + v * (minLength / length) / 2.0 end return bbox end function MR_CurveTool:TestMousePoint(moho, mouseEvent) -- Returns what mode the tool would be in if the user clicked at the current mouse location if (self.keyMovement) then return 0 end local mesh = moho:DrawingMesh() if (mesh == nil) then return 0 end local bbox = self:SelectedMeshBounds(moho, moho.drawingLayer, mesh, moho.drawingFrame, mouseEvent.view) local v = LM.Vector2:new_local() local pt = LM.Point:new_local() local m = LM.Matrix:new_local() moho.drawingLayer:GetFullTransform(moho.layerFrame, m, moho.document) -- test for uniform scaling v:Set(bbox.fMin.x, bbox.fMin.y) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then -- bottom left return 4 end v:Set(bbox.fMin.x, bbox.fMax.y) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then -- top left return 2 end v:Set(bbox.fMax.x, bbox.fMax.y) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then -- top right return 3 end v:Set(bbox.fMax.x, bbox.fMin.y) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then -- bottom right return 5 end -- test for X scaling v:Set(bbox.fMin.x, (bbox.fMin.y + bbox.fMax.y) * 0.5) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then -- left return 6 end v:Set(bbox.fMax.x, (bbox.fMin.y + bbox.fMax.y) * 0.5) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then -- right return 7 end -- test for Y scaling v:Set((bbox.fMin.x + bbox.fMax.x) * 0.5, bbox.fMin.y) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then -- bottom return 9 end v:Set((bbox.fMin.x + bbox.fMax.x) * 0.5, bbox.fMax.y) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then -- top return 8 end -- test for pivot point if (self.dragging) then v:Set(self.centerVec) else v = mesh:SelectedCenter() v = v + self.pivotOffset end m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then -- pivot point return 11 end local rotWidth = bbox.fMax.x - bbox.fMin.x if (bbox.fMax.y - bbox.fMin.y > rotWidth) then rotWidth = bbox.fMax.y - bbox.fMin.y end rotWidth = rotWidth * 0.1 if self.enableSkewTransformation then -- test for X skew v:Set(bbox.fMin.x - rotWidth, (bbox.fMin.y + bbox.fMax.y) * 0.5) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then -- left return 20 end v:Set(bbox.fMax.x + rotWidth, (bbox.fMin.y + bbox.fMax.y) * 0.5) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then -- right return 21 end -- test for Y skew v:Set((bbox.fMin.x + bbox.fMax.x) * 0.5, bbox.fMin.y - rotWidth) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then -- bottom return 22 end v:Set((bbox.fMin.x + bbox.fMax.x) * 0.5, bbox.fMax.y + rotWidth) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then -- top return 23 end end if self.enableDistortTransformation and self.selectedPoints > 2 then -- test for Distord v:Set(bbox.fMin.x - rotWidth, bbox.fMin.y - rotWidth) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then -- bottom left return 24 end v:Set(bbox.fMin.x - rotWidth, bbox.fMax.y + rotWidth) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then -- top left return 25 end v:Set(bbox.fMax.x + rotWidth, bbox.fMax.y + rotWidth) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then -- top right return 26 end v:Set(bbox.fMax.x + rotWidth, bbox.fMin.y - rotWidth) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then -- bottom right return 27 end end -- test for translation outside the bounding box if (mouseEvent.drawingVec.x < bbox.fMin.x - rotWidth or mouseEvent.drawingVec.x > bbox.fMax.x + rotWidth or mouseEvent.drawingVec.y < bbox.fMin.y - rotWidth or mouseEvent.drawingVec.y > bbox.fMax.y + rotWidth) then return 0, true end -- test for rotation if (mouseEvent.drawingVec.x < bbox.fMin.x or mouseEvent.drawingVec.x > bbox.fMax.x or mouseEvent.drawingVec.y < bbox.fMin.y or mouseEvent.drawingVec.y > bbox.fMax.y) then return 1 end return 0 -- translation inside the bounding box end function MR_CurveTool:OnMouseMoved_T(moho, mouseEvent) local mesh = moho:DrawingMesh() if (mesh == nil) then return end if (mouseEvent.ctrlKey) then -- hold down the control key to just select a single point and not move it return end self.endWeldVec:Set(-10000000, -10000000) local curVec = mouseEvent.drawingVec - mouseEvent.drawingStartVec if (mouseEvent.shiftKey) then if (math.abs(mouseEvent.drawingVec.x - mouseEvent.drawingStartVec.x) > math.abs(mouseEvent.drawingVec.y - mouseEvent.drawingStartVec.y)) then curVec.y = 0 else curVec.x = 0 end end if (moho.gridOn) then moho:SnapToGrid(curVec) end mesh:TranslatePoints(curVec) self:AddPointKeyframe(moho, moho.layerFrame) if self.fixedHandles then mesh:PreserveHandlePositions(moho.layerFrame) end self.transformation = true mouseEvent.view:DrawMe() end function MR_CurveTool:OnMouseMoved_S(moho, mouseEvent) if (self.numSel < 2) then return end local mesh = moho:DrawingMesh() if (mesh == nil) then return end local center = LM.Vector2:new_local() center:Set(self.centerVec) if (mouseEvent.altKey) then center:Set(self.centerVec) else if (self.mode == 6) then -- LEFT center:Set(self.selectedMax.x, (self.selectedMin.y + self.selectedMax.y) / 2.0) elseif (self.mode == 7) then -- RIGHT center:Set(self.selectedMin.x, (self.selectedMin.y + self.selectedMax.y) / 2.0) elseif (self.mode == 8) then -- TOP center:Set((self.selectedMin.x + self.selectedMax.x) / 2.0, self.selectedMin.y) elseif (self.mode == 9) then -- BOTTOM center:Set((self.selectedMin.x + self.selectedMax.x) / 2.0, self.selectedMax.y) elseif (self.mode == 4) then -- BL center:Set(self.selectedMax.x, self.selectedMax.y) elseif (self.mode == 2) then -- TL center:Set(self.selectedMax.x, self.selectedMin.y) elseif (self.mode == 3) then -- TR center:Set(self.selectedMin.x, self.selectedMin.y) elseif (self.mode == 5) then -- BR center:Set(self.selectedMin.x, self.selectedMax.y) end end local scaling = LM.Vector2:new_local() scaling:Set(1, 1) -- scaling connected to actual drag amount local v1 = mouseEvent.drawingStartVec - center local v2 = mouseEvent.drawingVec - center scaling.x = v2.x / v1.x scaling.y = v2.y / v1.y if (self.mode == 6 or self.mode == 7) then -- horizontal scaling scaling.y = 1 if (mouseEvent.shiftKey) then scaling.y = 1 / scaling.x end elseif (self.mode == 8 or self.mode == 9) then -- vertical scaling scaling.x = 1 if (mouseEvent.shiftKey) then scaling.x = 1 / scaling.y end else if (not mouseEvent.shiftKey) then scaling.x = (scaling.x + scaling.y) / 2 scaling.y = scaling.x end end local flip = false if (scaling.x * self.lastScaleX < -0.0001) then if (scaling.y * self.lastScaleY > 0.0001) then flip = true end elseif (scaling.y * self.lastScaleY < -0.0001) then if (scaling.x * self.lastScaleX > 0.0001) then flip = true end end mesh:ScalePoints(scaling.x, scaling.y, center, flip) self:AddPointKeyframe(moho, moho.layerFrame) local k = 1 if scaling.x * scaling.y < 0 then k = -1 end if (mouseEvent.altKey) then local v = mesh:SelectedCenter() self.pivotOffset = self.centerVec - v else local v = self.centerVec - center v.x = v.x * scaling.x v.y = v.y * scaling.y v = v + center self.pivotOffset = v - mesh:SelectedCenter() end if (flip) then self.lastScaleX = scaling.x self.lastScaleY = scaling.y end if self.fixedHandles then mesh:PreserveHandlePositions(moho.layerFrame) end self.transformation = true mouseEvent.view:DrawMe() end function MR_CurveTool:OnMouseMoved_R(moho, mouseEvent) local mesh = moho:DrawingMesh() if (mesh == nil) then return end local angle = self.startAngle local v1 = self.lastVec - self.centerVec local v2 = mouseEvent.drawingVec - self.centerVec v2:Rotate(-math.atan2(v1.y, v1.x)) angle = angle + math.atan2(v2.y, v2.x) self.startAngle = angle if (mouseEvent.shiftKey) then angle = angle / (math.pi / 4) angle = (math.pi / 4) * LM.Round(angle) end mesh:RotatePoints(angle, self.centerVec) self:AddPointKeyframe(moho, moho.layerFrame) self.lastVec:Set(mouseEvent.drawingVec) if self.fixedHandles then mesh:PreserveHandlePositions(moho.layerFrame) end self.transformation = true mouseEvent.view:DrawMe() end function MR_CurveTool:OnMouseMoved_P(moho, mouseEvent) local mesh = moho:DrawingMesh() if (mesh == nil) then return end local curVec = mouseEvent.drawingVec - mouseEvent.drawingStartVec if (mouseEvent.shiftKey) then if (math.abs(mouseEvent.drawingVec.x - mouseEvent.drawingStartVec.x) > math.abs(mouseEvent.drawingVec.y - mouseEvent.drawingStartVec.y)) then curVec.y = 0 else curVec.x = 0 end end self.pivotOffset = self.startPivotOffset + curVec self.centerVec = mesh:SelectedCenter() self.centerVec = self.centerVec + self.pivotOffset mouseEvent.view:DrawMe() end function MR_CurveTool:OnMouseMoved_Skew(moho, mouseEvent) local mesh = moho:DrawingMesh() if (mesh == nil) then return end local center = LM.Vector2:new_local() center:Set(self.centerVec) if (mouseEvent.altKey) then center:Set(self.centerVec) else if (self.mode == 20) then -- LEFT center:Set(self.selectedMax.x, (self.selectedMin.y + self.selectedMax.y) / 2.0) elseif (self.mode == 21) then -- RIGHT center:Set(self.selectedMin.x, (self.selectedMin.y + self.selectedMax.y) / 2.0) elseif (self.mode == 22) then -- TOP center:Set((self.selectedMin.x + self.selectedMax.x) / 2.0, self.selectedMax.y) elseif (self.mode == 23) then -- BOTTOM center:Set((self.selectedMin.x + self.selectedMax.x) / 2.0, self.selectedMin.y) end end local scaling = LM.Vector2:new_local() scaling:Set(1, 1) local v1 = mouseEvent.drawingStartVec local v2 = mouseEvent.drawingVec scaling.x = v2.x - v1.x scaling.y = v2.y - v1.y if (self.mode == 20 or self.mode == 21) then scaling.x = 1 elseif (self.mode == 22 or self.mode == 23) then scaling.y = 1 end local curVec = mouseEvent.drawingVec - mouseEvent.drawingStartVec for i, point in pairs(self.selList)do if self.mode == 20 then local divisor = self.minVec.x - center.x local newPos = LM.Vector2:new_local() local newX = point.fTempPos.x local newY = point.fTempPos.y + scaling.y * (point.fTempPos.x - center.x) / divisor point.fPos.x = newX point.fPos.y = newY elseif self.mode == 21 then local divisor = self.maxVec.x - center.x local newPos = LM.Vector2:new_local() local newX = point.fTempPos.x local newY = point.fTempPos.y + scaling.y * (point.fTempPos.x - center.x) / divisor point.fPos.x = newX point.fPos.y = newY elseif self.mode == 22 then local divisor = self.minVec.y - center.y local newPos = LM.Vector2:new_local() local newX = point.fTempPos.x + scaling.x * (point.fTempPos.y - center.y) / divisor local newY = point.fTempPos.y point.fPos.x = newX point.fPos.y = newY elseif self.mode == 23 then local divisor = self.maxVec.y - center.y local newPos = LM.Vector2:new_local() local newX = point.fTempPos.x + scaling.x * (point.fTempPos.y - center.y) / divisor local newY = point.fTempPos.y point.fPos.x = newX point.fPos.y = newY end end if (mouseEvent.altKey) then local v = mesh:SelectedCenter() self.pivotOffset = self.centerVec - v else if self.mode == 20 then local divisor = self.minVec.x - center.x local newPos = LM.Vector2:new_local() local newX = self.centerVec.x local newY = self.centerVec.y + scaling.y * (self.centerVec.x - center.x) / divisor newPos:Set(newX, newY) self.pivotOffset:Set(newPos - mesh:SelectedCenter()) elseif self.mode == 21 then local divisor = self.maxVec.x - center.x local newPos = LM.Vector2:new_local() local newX = self.centerVec.x local newY = self.centerVec.y + scaling.y * (self.centerVec.x - center.x) / divisor newPos:Set(newX, newY) self.pivotOffset:Set(newPos - mesh:SelectedCenter()) elseif self.mode == 22 then local divisor = self.minVec.y - center.y local newPos = LM.Vector2:new_local() local newX = self.centerVec.x + scaling.x * (self.centerVec.y - center.y) / divisor local newY = self.centerVec.y newPos:Set(newX, newY) self.pivotOffset:Set(newPos - mesh:SelectedCenter()) elseif self.mode == 23 then local divisor = self.maxVec.y - center.y local newPos = LM.Vector2:new_local() local newX = self.centerVec.x + scaling.x * (self.centerVec.y - center.y) / divisor local newY = self.centerVec.y newPos:Set(newX, newY) self.pivotOffset:Set(newPos - mesh:SelectedCenter()) end end self:AddPointKeyframe(moho, moho.layerFrame) self.lastVec:Set(mouseEvent.drawingVec) if self.fixedHandles then mesh:PreserveHandlePositions(moho.layerFrame) end self.transformation = true mouseEvent.view:DrawMe() end function MR_CurveTool:OnMouseMoved_Distort(moho, mouseEvent) local mesh = moho:DrawingMesh() if (mesh == nil) then return end self.transformation = true if self.mode == 25 then -- 'topLeft self.topLeft.x = mouseEvent.vec.x - (self.clickPos.x - self.minVec.x) self.topLeft.y = mouseEvent.vec.y - (self.clickPos.y - self.maxVec.y) elseif self.mode == 26 then -- topRight self.topRight.x = mouseEvent.vec.x - (self.clickPos.x - self.maxVec.x) self.topRight.y = mouseEvent.vec.y - (self.clickPos.y - self.maxVec.y) elseif self.mode == 27 then -- bottomRight self.bottomRight.x = mouseEvent.vec.x - (self.clickPos.x - self.maxVec.x) self.bottomRight.y = mouseEvent.vec.y - (self.clickPos.y - self.minVec.y) elseif self.mode == 24 then -- bottomLeft self.bottomLeft.x = mouseEvent.vec.x - (self.clickPos.x - self.minVec.x) self.bottomLeft.y = mouseEvent.vec.y - (self.clickPos.y - self.minVec.y) end for k, v in pairs(self.ptlist)do local topPoint = LM.Vector2:new_local() local bottomPoint = LM.Vector2:new_local() local leftPoint = LM.Vector2:new_local() local rightPoint = LM.Vector2:new_local() local topAngle = math.atan2(self.topRight.y - self.topLeft.y, self.topRight.x - self.topLeft.x) local dx = self.topRight.x - self.topLeft.x local dy = self.topRight.y - self.topLeft.y local topdist = math.sqrt(dx * dx + dy * dy) topPoint.x = self.topLeft.x + math.cos(topAngle) * (topdist * self.horizonPercent[k]) topPoint.y = self.topLeft.y + math.sin(topAngle) * (topdist * self.horizonPercent[k]) local bottomAngle = math.atan2(self.bottomRight.y - self.bottomLeft.y, self.bottomRight.x - self.bottomLeft.x) local dx = self.bottomRight.x - self.bottomLeft.x local dy = self.bottomRight.y - self.bottomLeft.y local bottomdist = math.sqrt(dx * dx + dy * dy) bottomPoint.x = self.bottomLeft.x + math.cos(bottomAngle) * (bottomdist * self.horizonPercent[k]) bottomPoint.y = self.bottomLeft.y + math.sin(bottomAngle) * (bottomdist * self.horizonPercent[k]) local leftAngle = math.atan2(self.bottomLeft.y - self.topLeft.y, self.bottomLeft.x - self.topLeft.x) local dx = self.bottomLeft.x - self.topLeft.x local dy = self.bottomLeft.y - self.topLeft.y local leftdist = math.sqrt(dx * dx + dy * dy) leftPoint.x = self.topLeft.x + math.cos(leftAngle) * (leftdist * self.vertPercent[k]) leftPoint.y = self.topLeft.y + math.sin(leftAngle) * (leftdist * self.vertPercent[k]) local rightAngle = math.atan2(self.bottomRight.y - self.topRight.y, self.bottomRight.x - self.topRight.x) local dx = self.bottomRight.x - self.topRight.x local dy = self.bottomRight.y - self.topRight.y local rightdist = math.sqrt(dx * dx + dy * dy) rightPoint.x = self.topRight.x + math.cos(rightAngle) * (rightdist * self.vertPercent[k]) rightPoint.y = self.topRight.y + math.sin(rightAngle) * (rightdist * self.vertPercent[k]) local a1, a2, b1, b2, c1, c2 a1 = bottomPoint.y - topPoint.y b1 = topPoint.x - bottomPoint.x c1 = bottomPoint.x * topPoint.y - topPoint.x * bottomPoint.y a2 = rightPoint.y - leftPoint.y b2 = leftPoint.x - rightPoint.x c2 = rightPoint.x * leftPoint.y - leftPoint.x * rightPoint.y local denom =a1 * b2 - a2 * b1; local newPos = LM.Vector2:new_local() newPos:Set((b1 * c2 - b2 * c1) / denom, (a2 * c1 - a1 * c2) / denom) v.fPos.x = newPos.x v.fPos.y = newPos.y end self:AddPointKeyframe(moho, moho.layerFrame) local topPoint = LM.Vector2:new_local() local bottomPoint = LM.Vector2:new_local() local leftPoint = LM.Vector2:new_local() local rightPoint = LM.Vector2:new_local() local topAngle = math.atan2(self.topRight.y - self.topLeft.y, self.topRight.x - self.topLeft.x) local dx = self.topRight.x - self.topLeft.x local dy = self.topRight.y - self.topLeft.y local topdist = math.sqrt(dx * dx + dy * dy) topPoint.x = self.topLeft.x + math.cos(topAngle) * (topdist * self.horizonPercentCenter) topPoint.y = self.topLeft.y + math.sin(topAngle) * (topdist * self.horizonPercentCenter) local bottomAngle = math.atan2(self.bottomRight.y - self.bottomLeft.y, self.bottomRight.x - self.bottomLeft.x) local dx = self.bottomRight.x - self.bottomLeft.x local dy = self.bottomRight.y - self.bottomLeft.y local bottomdist = math.sqrt(dx * dx + dy * dy) bottomPoint.x = self.bottomLeft.x + math.cos(bottomAngle) * (bottomdist * self.horizonPercentCenter) bottomPoint.y = self.bottomLeft.y + math.sin(bottomAngle) * (bottomdist * self.horizonPercentCenter) local leftAngle = math.atan2(self.bottomLeft.y - self.topLeft.y, self.bottomLeft.x - self.topLeft.x) local dx = self.bottomLeft.x - self.topLeft.x local dy = self.bottomLeft.y - self.topLeft.y local leftdist = math.sqrt(dx * dx + dy * dy) leftPoint.x = self.topLeft.x + math.cos(leftAngle) * (leftdist * self.vertPercentCenter) leftPoint.y = self.topLeft.y + math.sin(leftAngle) * (leftdist * self.vertPercentCenter) local rightAngle = math.atan2(self.bottomRight.y - self.topRight.y, self.bottomRight.x - self.topRight.x) local dx = self.bottomRight.x - self.topRight.x local dy = self.bottomRight.y - self.topRight.y local rightdist = math.sqrt(dx * dx + dy * dy) rightPoint.x = self.topRight.x + math.cos(rightAngle) * (rightdist * self.vertPercentCenter) rightPoint.y = self.topRight.y + math.sin(rightAngle) * (rightdist * self.vertPercentCenter) local a1, a2, b1, b2, c1, c2 a1 = bottomPoint.y - topPoint.y b1 = topPoint.x - bottomPoint.x c1 = bottomPoint.x * topPoint.y - topPoint.x * bottomPoint.y a2 = rightPoint.y - leftPoint.y b2 = leftPoint.x - rightPoint.x c2 = rightPoint.x * leftPoint.y - leftPoint.x * rightPoint.y local denom = a1 * b2 - a2 * b1 local newPos = LM.Vector2:new_local() newPos:Set((b1 * c2 - b2 * c1) / denom, (a2 * c1 - a1 * c2) / denom) self.pivotOffset:Set(newPos - mesh:SelectedCenter()) self.lastVec:Set(mouseEvent.drawingVec) if self.fixedHandles then mesh:PreserveHandlePositions(moho.layerFrame) end mouseEvent.view:DrawMe() end function MR_CurveTool:PreviewWeldPoint(moho, mouseEvent, point) local mesh = moho:DrawingMesh() if (mesh == nil) then return end local m = LM.Matrix:new_local() local testVec1 = LM.Vector2:new_local() local p1 = LM.Point:new_local() local testVec2 = LM.Vector2:new_local() local p2 = LM.Point:new_local() local dist = 0 local curveID = -1 local segID = -1 local pickWidth = 5 self.endWeldVec:Set(-10000000, -10000000) testVec1:Set(point.fPos) moho.drawingLayer:GetFullTransform(moho.layerFrame, m, moho.document) m:Transform(testVec1) moho.view:Graphics():WorldToScreen(testVec1, p1) self.drawWeldPoint = false local closestID = mesh:ClosestPoint(point.fPos, self.selectedPointID) if (closestID >= 0) then testVec2:Set(mesh:Point(closestID).fPos) m:Transform(testVec2) moho.view:Graphics():WorldToScreen(testVec2, p2) dist = (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y) local curve, where = point:Curve(point:CountCurves()-1, -1) local pointCurveID = curve:PointID(point) local prewPointID = -1 if pointCurveID == 0 then pointCurveID = 1 else pointCurveID = pointCurveID -1 end local prewPoint = curve:Point(pointCurveID) if self.autoWeld or (not self.autoWeld and mouseEvent.altKey) then if (dist < self.autoWeldRadius * 1.5 and (not mesh:ArePointsAdjacent(self.selectedPointID, closestID))) and (not mesh:ArePointsAdjacent(mesh:PointID(prewPoint), closestID) or not self:ArePointsConnected(moho, mesh, mesh:Point(self.selectedPointID), mesh:Point(closestID))) then self.endWeldToPoint = true self.endWeldVec:Set(mesh:Point(closestID).fPos) self.drawWeldPoint = true elseif dist > self.autoWeldRadius * 1.5 then curveID, segID = point:GetEndpointEdge(curveID, segID) curveID, segID = moho.view:PickEdge(p1, curveID, segID, pickWidth) if (curveID >= 0) then -- add a point in the middle of some curve if ((not mesh:Curve(curveID):IsPointOnSegment(self.selectedPointID, segID)) and (not mesh:Curve(curveID):IsPointOnSegment(self.selectedPointID, segID - 1)) and (not mesh:Curve(curveID):IsPointOnSegment(self.selectedPointID, segID + 1))) then -- don't weld the point back on itself self.endWeldToPoint = false self.endWeldVec:Set(mesh:Curve(curveID):ClosestPointOnSegment(segID, point.fPos, true, true)) self.drawWeldPoint = true end end end end end end function MR_CurveTool:WeldPoints(moho, event, vec, forceWeld) local mesh = moho:DrawingMesh() if (mesh == nil) then return false end if moho.drawingLayer:CurrentAction() ~= "" then return end local testVec1 = LM.Vector2:new_local() testVec1:Set(vec) local autoWeld = self.autoWeld if forceWeld then autoWeld = true end local drawingClosestID = mesh:ClosestPoint(testVec1, self.selectedPointID) local drawingClosest = self:GetColosestVec(moho, event.view, testVec1, mesh:Point(drawingClosestID).fPos) local point = mesh:Point(self.selectedPointID) if drawingClosest < self.autoWeldRadius * 1.5 then if ((autoWeld and not event.altKey) or (not autoWeld and event.altKey)) and self.drawingStatus then local curve, where = point:Curve(point:CountCurves()-1, -1) local pointCurveID = where if pointCurveID == 0 then pointCurveID = 1 else pointCurveID = pointCurveID -1 end local prewPoint = curve:Point(pointCurveID) local isPointsOnOneCurve = false isPointsOnOneCurve = self:ArePointsConnected(moho, mesh, mesh:Point(drawingClosestID), point) if not mesh:ArePointsAdjacent(drawingClosestID, self.selectedPointID) and not mesh:ArePointsAdjacent(mesh:PointID(prewPoint), drawingClosestID) then if mesh:WeldPoints(self.selectedPointID, drawingClosestID, moho.layerFrame) then if isPointsOnOneCurve then if curve.fClosed then self.weldedCurve = curve end end if not self.singleCurveMode then self:ClearPointKeys(moho, self.selectedPointID) self.selectedPointID = -1 mesh:SelectNone() self.drawingStatus = false else self.secondPointID = drawingClosestID end self.drawWeldPoint = false moho:Click() moho:UpdateUI() return true end end end elseif drawingClosest > self.autoWeldRadius * 1.5 then if ((autoWeld and not event.altKey) or (not autoWeld and event.altKey)) and self.drawingStatus then local m = LM.Matrix:new_local() local v = LM.Vector2:new_local() local pt = LM.Point:new_local() local curveID = -1 local segID = -1 local pickWidth = 5 moho.drawingLayer:GetFullTransform(moho.layerFrame, m, moho.document) local point = mesh:Point(self.selectedPointID) v:Set(point.fPos) m:Transform(v) event.view:Graphics():WorldToScreen(v, pt) curveID, segID = point:GetEndpointEdge(curveID, segID) curveID, segID = moho.view:PickEdge(pt, curveID, segID, pickWidth) local originalCurve = point:Curve(0, -1) if (curveID >= 0 and (autoWeld or (not autoWeld and event.altKey))) then -- add a point in the middle of some curve if (not mesh:Curve(curveID):IsPointOnSegment(self.selectedPointID, segID)) and (not mesh:Curve(curveID):IsPointOnSegment(self.selectedPointID, segID - 1)) and (not mesh:Curve(curveID):IsPointOnSegment(self.selectedPointID, segID + 1)) then local curve = mesh:Curve(curveID) mesh:AddPoint(curve:ClosestPointOnSegment(segID, point.fPos, true, true), curveID, segID, moho.layerFrame) mesh:WeldPoints(self.selectedPointID, mesh:CountPoints() - 1, moho.layerFrame) moho:Click() self.drawWeldPoint = false local newPoint = mesh:Point(mesh:CountPoints() - 1) local curve, where = newPoint:Curve(newPoint:CountCurves()-1, -1) local newPointCurveID = curve:PointID(newPoint) if newPointCurveID ~= 0 then newPointCurveID = curve:CountPoints()-1 end self.weldedCurve = originalCurve if (event.ctrlKey and not self.sharpCorners) or (not event.ctrlKey and self.sharpCorners) then curve:SetCurvature(newPointCurveID, MOHO.PEAKED + self.peakedCorner, moho.layerFrame) end self:ClearPointKeys(moho, self.selectedPointID) if not self.singleCurveMode then self.drawingStatus = false self.selectedPointID = -1 end mesh:SelectNone() moho:UpdateUI() return true end end end end return false end function MR_CurveTool:AddPointKeyframe(moho, frame, layer, allSelectedKeys) for i, pt in pairs(self.selList) do self.fPoses[i]:Set(pt.fPos) end moho:AddPointKeyframe(frame, layer, allSelectedKeys) for i, pt in pairs(self.selList) do local delta = self.fPoses[i] - pt.fPos pt.fPos = self.fPoses[i] + delta end moho:AddPointKeyframe(frame, layer, allSelectedKeys) end function MR_CurveTool:FixHandles(moho, mesh) -- This code is copied from Alexandra Evseeva's scripts. self.bezierList = {} for c=0, mesh:CountCurves()-1 do local nextCurveArray = {} for p=0, mesh:Curve(c):CountPoints()-1 do local preVect = mesh:Curve(c):GetControlHandle(p, moho.layerFrame, true) local postVect = mesh:Curve(c):GetControlHandle(p, moho.layerFrame, false) local pointArray = {pre = preVect, post = postVect} nextCurveArray[p] = pointArray end self.bezierList[c] = nextCurveArray end end function MR_CurveTool:PopulateSelList(moho, mesh) self.fPoses = {} self.selList = {} self.inOffsets = {} self.outOffsets = {} for i = 0, mesh:CountPoints() - 1 do local pt = mesh:Point(i) if pt.fSelected then table.insert(self.selList, pt) table.insert(self.fPoses, LM.Vector2:new_local()) local ins = {} local outs = {} for c = 0, pt:CountCurves() -1 do local curve, where = pt:Curve(c, -1) ins[c] = curve:GetOffset(where, moho.layerFrame, true) outs[c] = curve:GetOffset(where, moho.layerFrame, false) end table.insert(self.inOffsets, ins) table.insert(self.outOffsets, outs) end end end function MR_CurveTool:RepairFixedHandles(moho, mesh) -- This code is copied from Alexandra Evseeva's scripts. if not self.bezierList then return end local precision = 0.0000001 for k,v in pairs(self.bezierList) do local nextCurve = mesh:Curve(k) if nextCurve == nil then return end for n,p in pairs(v) do local point = nextCurve:Point(n) if not point then return end if not point.fSelected then local preVect = nextCurve:GetControlHandle(n, moho.drawingLayerFrame, true) local postVect = nextCurve:GetControlHandle(n, moho.drawingLayerFrame, false) local preChanged = ((p.pre - preVect):Mag()>precision) local postChanged = ((p.post - postVect):Mag()>precision) if preChanged or postChanged then for ind, isChanged in pairs({preChanged, postChanged}) do local isPreHandle = (ind == 1) local targetOffset = nextCurve:GetOffset(n, moho.layerFrame, isPreHandle) local targetWeight = nextCurve:GetWeight(n, moho.layerFrame, isPreHandle) local currentOffset = AE_Utilities:GetOffsetChannel(moho, moho.drawingLayer, nextCurve, n, isPreHandle).value local currentWeight = AE_Utilities:GetWeightChannel(moho, moho.drawingLayer, nextCurve, n, isPreHandle).value local offsetDelta = currentOffset - targetOffset if self.flipDirectionList[mesh:PointID(point) + 1] then offsetDelta = -currentOffset + targetOffset end nextCurve:SetOffset(n, targetOffset - offsetDelta, moho.layerFrame, isPreHandle) local weightDelta = currentWeight - targetWeight nextCurve:SetWeight(n, targetWeight - weightDelta, moho.layerFrame, isPreHandle) moho.layer:UpdateCurFrame() end end end end end end function MR_CurveTool:CheckFlipDirection(moho, point) if not point then return end local flipDirection = false local flipDirectionV = false local curve, where = point:Curve(0, -1) local parent = point.fParent local originalOffset = AE_Utilities:GetOffsetChannel(moho, moho.drawingLayer, curve, where, true).value point.fParent = -1 moho.drawingLayer:UpdateCurFrame() local newOffset = AE_Utilities:GetOffsetChannel(moho, moho.drawingLayer, curve, where, true).value point.fParent = parent if self.mohoVersion >= 14 then if originalOffset ~= newOffset or (tostring(originalOffset) == '-0.0' and tostring(newOffset) == '0.0') or (tostring(originalOffset) == '0.0' and tostring(newOffset) == '-0.0') then flipDirection = true end else if originalOffset ~= newOffset or (originalOffset == -0 and newOffset == 0) or (originalOffset == 0 and newOffset == -0) then flipDirection = true end end return flipDirection end function MR_CurveTool:MakeFlipDirectionList(moho) self.flipDirectionList = {} local mesh = moho:DrawingMesh() if (mesh == nil) then return end for c=0, mesh:CountCurves()-1 do local curve = mesh:Curve(c) if curve:IsPartiallySelected() then local curvePoints = curve:CountPoints() for p=0, curvePoints - 1 do local point = curve:Point(p) if not point.fSelected then local areAdjacentPointsSelected = false if curve.fClosed then if p == 0 then if curve:Point(curvePoints - 1).fSelected or curve:Point(p + 1).fSelected then areAdjacentPointsSelected = true end elseif p == curvePoints - 1 then if curve:Point(0).fSelected or curve:Point(p - 1).fSelected then areAdjacentPointsSelected = true end else if curve:Point(p + 1).fSelected or curve:Point(p - 1).fSelected then areAdjacentPointsSelected = true end end else if p == 0 then if curve:Point(p + 1).fSelected then areAdjacentPointsSelected = true end elseif p == curvePoints - 1 then if curve:Point(p - 1).fSelected then areAdjacentPointsSelected = true end else if curve:Point(p + 1).fSelected or curve:Point(p - 1).fSelected then areAdjacentPointsSelected = true end end end if areAdjacentPointsSelected then local flipDirection = self:CheckFlipDirection(moho, point) self.flipDirectionList[mesh:PointID(point)+1] = flipDirection end end end end end moho.drawingLayer:UpdateCurFrame() end function MR_CurveTool:FixFBF(moho) local mesh = moho:DrawingMesh() if (mesh == nil) then return end local layer = moho.drawingLayer layer:CopyFrame(moho.layerFrame, 0, falae) layer:ClearAnimation(false, 0, falae) end function MR_CurveTool:SingleClickSelect(moho, mouseEvent, tryToPreserveSelection, allowEmptySelection) -- if tryToPreserveSelection is true, then don't change the selection if some points will remain selected local mesh = moho:DrawingMesh() if (mesh == nil) then return end if (tryToPreserveSelection and moho:CountSelectedPoints() < 2) then mesh:SelectNone() moho:CountSelectedPoints(true) end if (not tryToPreserveSelection and not mouseEvent.shiftKey and not mouseEvent.altKey) then mesh:SelectNone() end local i = mouseEvent.view:PickPoint(mouseEvent.pt) if (i >= 0) then --pick a point self.selMode = self.SELMODE_PT if (tryToPreserveSelection) then if (not mesh:Point(i).fSelected) then mesh:SelectNone() end end if (mouseEvent.altKey) then mesh:Point(i).fSelected = false else mesh:Point(i).fSelected = true end else if (tryToPreserveSelection) then for i = 0, mesh:CountPoints() - 1 do local point = mesh:Point(i) point.fPrevSelected = point.fSelected point.fSelected = false end end local curveID = -1 local segID = -1 curveID, segID = mouseEvent.view:PickEdge(mouseEvent.pt, curveID, segID) if (curveID >= 0 and segID >= 0) then -- an edge was clicked on self.selMode = SELMODE_EDGE local curve = mesh:Curve(curveID) -- new method - select the points in the curve that was clicked on if (mouseEvent.altKey) then local isCurveSelected = true for i = 0, curve:CountPoints() - 1 do if (not curve:Point(i).fSelected) then isCurveSelected = false break end end for i = 0, curve:CountPoints() - 1 do local point = curve:Point(i) if ((not isCurveSelected) or (point:CountCurves() < 2)) then point.fSelected = false if (point.fHidden) then point.fSelected = false end end end else for i = 0, curve:CountPoints() - 1 do local point = curve:Point(i) if (not point.fHidden) then point.fSelected = true end end end elseif (self.allowShapePicking) then -- try to pick a shape local shapeID = mouseEvent.view:PickShape(mouseEvent.pt) if (shapeID >= 0) then self.selMode = SELMODE_SHAPE -- select (or deselect) everything connected to the shape local shape = mesh:Shape(shapeID) for i = 0, shape:CountEdges() - 1 do curveID, segID = shape:GetEdge(i, curveID, segID) local curve = mesh:Curve(curveID) if (mouseEvent.altKey) then curve:Point(segID).fSelected = false curve:Point(segID + 1).fSelected = false else curve:Point(segID).fSelected = true curve:Point(segID + 1).fSelected = true end end end end if (not allowEmptySelection) then local numSel = moho:CountSelectedPoints(true) if (numSel < 1) then for i = 0, mesh:CountPoints() - 1 do local point = mesh:Point(i) point.fSelected = point.fPrevSelected point.fPrevSelected = false end end end if (tryToPreserveSelection) then local preserveSelection = false -- pass 1 - check if any of the selection is still selected for i = 0, mesh:CountPoints() - 1 do local point = mesh:Point(i) if (point.fPrevSelected and point.fSelected) then preserveSelection = true end end -- pass 2 - preserve the selection if (preserveSelection) then for i = 0, mesh:CountPoints() - 1 do local point = mesh:Point(i) point.fSelected = point.fPrevSelected point.fPrevSelected = false end else for i = 0, mesh:CountPoints() - 1 do local point = mesh:Point(i) point.fPrevSelected = false end end end end moho:UpdateSelectedChannels() end -- ************************************************** -- Localization -- ************************************************** function MR_CurveTool:Localize(text) local phrase = {} phrase['Description'] = 'Create points with a click. Ctrl - create a sharp corner. Alt - disable auto-welding. Backspace - remove the last point. Enter or double-click - finish the curve.' phrase['UILabel'] = 'Curve Tool 4.1' phrase['Settings'] = 'Settings' phrase['Draw in zero frame'] = 'Draw in zero frame' phrase['Draw in non zero frames'] = 'Draw in non zero frames' phrase['Always draw on FBF'] = 'Always draw on FBF' phrase['Draw behind'] = 'Draw behind' phrase['Use Peak for corners'] = 'Use Peak for corners' phrase['Use Peak for corners Tooltip'] = 'Sharp Corners will have a curvature value of 0 instead of 0.0001, however, this may lead to issues when adding new points to adjacent segments.' phrase['Show all handles'] = 'Show all handles' phrase['Enable skew transformation'] = 'Enable skew transformation' phrase['Enable distort transformation'] = 'Enable distort transformation' phrase['Click to select'] = 'Click to select' phrase['Single curve mode'] = 'Single curve mode' phrase['Curve mode'] = 'Curve mode' phrase['Points'] = 'Points:' phrase['Curvature'] = 'Curvature:' phrase['Show handles tooltip'] = 'Show handles' phrase['Fixed handles tooltip'] = 'Fixed bezier handles' phrase['Bezier drawing mode'] = 'Bezier drawing mode' phrase['Threshold'] = 'Threshold:' phrase['Auto-weld'] = 'Auto-weld' phrase['Sharp corners'] = 'Sharp corners' phrase['Auto-fill:'] = 'Auto-fill:' phrase['Auto-stroke:'] = 'Auto-stroke:' phrase['Width:'] = 'Width:' phrase['Set pivot to left up corner'] = 'Set pivot to left up corner' phrase['Set pivot to left'] = 'Set pivot to left' phrase['Set pivot to left down corner'] = 'Set pivot to left down corner' phrase['Set pivot to up'] = 'Set pivot to up' phrase['Set pivot to center'] = 'Set pivot to center' phrase['Set pivot to down'] = 'Set pivot to down' phrase['Set pivot to right up corner'] = 'Set pivot to right up corner' phrase['Set pivot to right'] = 'Set pivot to right' phrase['Set pivot to right down corner'] = 'Set pivot to right down corner' return phrase[text] end
MR Curve Tool
Listed
Author: eugenebabich
View Script
Script type: Tool
Uploaded: Jun 19 2022, 08:59
Last modified: Nov 14 2024, 08:27
Script Version: 4.1.3
This tool allows you to create points in Moho by just clicking the left mouse button instead of dragging and holding.
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: 3494
MR Curve Tool
Listed
Author: eugenebabich
View Script
Script type: Tool
Uploaded: Jun 19 2022, 08:59
Last modified: Nov 14 2024, 08:27
Script Version: 4.1.3
This tool allows you to create points in Moho by just clicking the left mouse button instead of dragging and holding.
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: 3494