Add stabilizer (fix #2371)

This commit is contained in:
David Capello 2021-06-11 09:08:12 -03:00
parent 83d8cfc33f
commit 1fd2e97b8d
6 changed files with 59 additions and 5 deletions

View File

@ -576,6 +576,8 @@ as = As:
merged_layers = Duplicate merged layers only
[dynamics]
stabilizer = Stabilizer
stabilizer_tooltip = Stabilizer radius to avoid shaky lines
pressure = Pressure
pressure_tooltip = Control parameters through the pen pressure sensor
velocity = Velocity

View File

@ -1,7 +1,14 @@
<!-- Aseprite -->
<!-- Copyright (C) 2020 Igara Studio S.A. -->
<!-- Copyright (C) 2020-2021 Igara Studio S.A. -->
<gui>
<vbox id="dynamics">
<hbox>
<check id="stabilizer" text="@.stabilizer"
tooltip="@.stabilizer_tooltip" tooltip_dir="bottom" />
<slider id="stabilizer_factor" value="16" min="0" max="64" expansive="true" style="mini_slider"
tooltip="@.stabilizer_tooltip" tooltip_dir="bottom" />
</hbox>
<hbox>
<buttonset id="values" columns="3">
<item text="" />

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2020-2021 Igara Studio S.A.
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -25,6 +25,7 @@ namespace tools {
};
struct DynamicsOptions {
int stabilizerFactor = 0;
DynamicSensor size = DynamicSensor::Static;
DynamicSensor angle = DynamicSensor::Static;
DynamicSensor gradient = DynamicSensor::Static;

View File

@ -30,6 +30,7 @@
#include "gfx/region.h"
#include <climits>
#include <cmath>
#define TOOL_TRACE(...) // TRACEARGS(__VA_ARGS__)
@ -118,6 +119,8 @@ void ToolLoopManager::pressButton(const Pointer& pointer)
return;
}
m_stabilizerCenter = pointer.point();
Stroke::Pt spritePoint = getSpriteStrokePt(pointer);
m_toolLoop->getController()->pressButton(m_toolLoop, m_stroke, spritePoint);
@ -163,8 +166,27 @@ bool ToolLoopManager::releaseButton(const Pointer& pointer)
return res;
}
void ToolLoopManager::movement(const Pointer& pointer)
void ToolLoopManager::movement(Pointer pointer)
{
// Filter points with the stabilizer
if (m_dynamics.stabilizerFactor > 0) {
const double f = m_dynamics.stabilizerFactor;
const gfx::Point delta = (pointer.point() - m_stabilizerCenter);
const double distance = std::sqrt(delta.x*delta.x + delta.y*delta.y);
const double angle = std::atan2(delta.y, delta.x);
const gfx::PointF newPoint(m_stabilizerCenter.x + distance/f*std::cos(angle),
m_stabilizerCenter.y + distance/f*std::sin(angle));
m_stabilizerCenter = newPoint;
pointer = Pointer(gfx::Point(newPoint),
pointer.velocity(),
pointer.button(),
pointer.type(),
pointer.pressure());
}
m_lastPointer = pointer;
if (isCanceled())

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2019-2021 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
@ -76,7 +76,7 @@ public:
bool releaseButton(const Pointer& pointer);
// Should be called each time the user moves the mouse inside the editor.
void movement(const Pointer& pointer);
void movement(Pointer pointer);
const Pointer& lastPointer() const { return m_lastPointer; }
@ -97,6 +97,7 @@ private:
gfx::Region m_nextDirtyArea;
doc::Brush m_brush0;
DynamicsOptions m_dynamics;
gfx::PointF m_stabilizerCenter;
};
} // namespace tools

View File

@ -215,6 +215,19 @@ DynamicsPopup::DynamicsPopup(Delegate* delegate)
, m_ditheringSel(new DitheringSelector(DitheringSelector::SelectMatrix))
, m_fromTo(tools::ColorFromTo::BgToFg)
{
m_dynamics->stabilizer()->Click.connect(
[this](){
if (m_dynamics->stabilizer()->isSelected() &&
m_dynamics->stabilizerFactor()->getValue() == 0) {
// TODO default value when we enable stabilizer when it's zero
m_dynamics->stabilizerFactor()->setValue(16);
}
});
m_dynamics->stabilizerFactor()->Change.connect(
[this](){
m_dynamics->stabilizer()->setSelected(m_dynamics->stabilizerFactor()->getValue() > 0);
});
m_dynamics->values()->ItemChange.connect(
[this](ButtonSet::Item* item){
onValuesChange(item);
@ -254,6 +267,14 @@ DynamicsPopup::DynamicsPopup(Delegate* delegate)
tools::DynamicsOptions DynamicsPopup::getDynamics() const
{
tools::DynamicsOptions opts;
if (m_dynamics->stabilizer()->isSelected()) {
opts.stabilizerFactor = m_dynamics->stabilizerFactor()->getValue();
}
else {
opts.stabilizerFactor = 0;
}
opts.size =
(isCheck(SIZE_WITH_PRESSURE) ? tools::DynamicSensor::Pressure:
isCheck(SIZE_WITH_VELOCITY) ? tools::DynamicSensor::Velocity: