Add brush snap to Grid toolbar option

This commit is contained in:
manongjohn 2021-11-03 23:46:49 -04:00
parent ee8fc57567
commit fa61b14844
7 changed files with 424 additions and 366 deletions

View file

@ -60,6 +60,7 @@ TEnv::DoubleVar FullcolorModifierOpacity("FullcolorModifierOpacity", 100);
TEnv::IntVar FullcolorModifierEraser("FullcolorModifierEraser", 0); TEnv::IntVar FullcolorModifierEraser("FullcolorModifierEraser", 0);
TEnv::IntVar FullcolorModifierLockAlpha("FullcolorModifierLockAlpha", 0); TEnv::IntVar FullcolorModifierLockAlpha("FullcolorModifierLockAlpha", 0);
TEnv::StringVar FullcolorBrushPreset("FullcolorBrushPreset", "<custom>"); TEnv::StringVar FullcolorBrushPreset("FullcolorBrushPreset", "<custom>");
TEnv::IntVar FullcolorBrushSnapGrid("FullcolorBrushSnapGrid", 0);
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -135,7 +136,8 @@ FullColorBrushTool::FullColorBrushTool(std::string name)
, m_tileSaver(0) , m_tileSaver(0)
, m_notifier(0) , m_notifier(0)
, m_presetsLoaded(false) , m_presetsLoaded(false)
, m_firstTime(true) { , m_firstTime(true)
, m_snapGrid("Grid", false) {
bind(TTool::RasterImage | TTool::EmptyTarget); bind(TTool::RasterImage | TTool::EmptyTarget);
m_thickness.setNonLinearSlider(); m_thickness.setNonLinearSlider();
@ -148,12 +150,14 @@ FullColorBrushTool::FullColorBrushTool(std::string name)
m_prop.bind(m_modifierEraser); m_prop.bind(m_modifierEraser);
m_prop.bind(m_modifierLockAlpha); m_prop.bind(m_modifierLockAlpha);
m_prop.bind(m_pressure); m_prop.bind(m_pressure);
m_prop.bind(m_snapGrid);
m_prop.bind(m_preset); m_prop.bind(m_preset);
m_preset.setId("BrushPreset"); m_preset.setId("BrushPreset");
m_modifierEraser.setId("RasterEraser"); m_modifierEraser.setId("RasterEraser");
m_modifierLockAlpha.setId("LockAlpha"); m_modifierLockAlpha.setId("LockAlpha");
m_pressure.setId("PressureSensitivity"); m_pressure.setId("PressureSensitivity");
m_snapGrid.setId("SnapGrid");
m_brushTimer.start(); m_brushTimer.start();
} }
@ -192,6 +196,7 @@ void FullColorBrushTool::updateTranslation() {
m_modifierOpacity.setQStringName(tr("Opacity")); m_modifierOpacity.setQStringName(tr("Opacity"));
m_modifierEraser.setQStringName(tr("Eraser")); m_modifierEraser.setQStringName(tr("Eraser"));
m_modifierLockAlpha.setQStringName(tr("Lock Alpha")); m_modifierLockAlpha.setQStringName(tr("Lock Alpha"));
m_snapGrid.setQStringName(tr("Grid"));
} }
//--------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------
@ -336,12 +341,16 @@ void FullColorBrushTool::leftButtonDown(const TPointD &pos,
} }
if (e.isAltPressed()) { if (e.isAltPressed()) {
m_snapAssistant = true;
m_isStraight = true; m_isStraight = true;
m_firstPoint = pos; m_firstPoint = pos;
m_lastPoint = pos; m_lastPoint = pos;
} }
if (m_snapGrid.getValue()) {
m_firstPoint = pos;
m_lastPoint = pos;
}
/* update color here since the current style might be switched with numpad /* update color here since the current style might be switched with numpad
* shortcut keys */ * shortcut keys */
updateCurrentStyle(); updateCurrentStyle();
@ -384,6 +393,7 @@ void FullColorBrushTool::leftButtonDown(const TPointD &pos,
invalidateRect += invalidateRect +=
TRectD(previousBrushPos - thickOffset, previousBrushPos + thickOffset); TRectD(previousBrushPos - thickOffset, previousBrushPos + thickOffset);
invalidate(invalidateRect.enlarge(2.0)); invalidate(invalidateRect.enlarge(2.0));
m_perspectiveIndex = -1;
} }
//------------------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------------
@ -391,16 +401,27 @@ void FullColorBrushTool::leftButtonDown(const TPointD &pos,
void FullColorBrushTool::leftButtonDrag(const TPointD &pos, void FullColorBrushTool::leftButtonDrag(const TPointD &pos,
const TMouseEvent &e) { const TMouseEvent &e) {
TRectD invalidateRect; TRectD invalidateRect;
if (m_isStraight) { invalidateRect = TRectD(m_firstPoint, m_lastPoint).enlarge(2);
invalidateRect = TRectD(m_firstPoint, m_lastPoint).enlarge(2); m_lastPoint = pos;
m_lastPoint = pos; TPointD usePos = pos;
if (e.isAltPressed()) {
double distance = (m_brushPos.x - m_maxCursorThick + 1) * 0.5;
TRectD brushRect =
TRectD(TPointD(m_brushPos.x - distance, m_brushPos.y - distance),
TPointD(m_brushPos.x + distance, m_brushPos.y + distance));
invalidateRect += (brushRect);
if (e.isAltPressed() || m_snapGrid.getValue()) {
double distance = (m_brushPos.x - m_maxCursorThick + 1) * 0.5;
TRectD brushRect =
TRectD(TPointD(m_brushPos.x - distance, m_brushPos.y - distance),
TPointD(m_brushPos.x + distance, m_brushPos.y + distance));
invalidateRect += (brushRect);
PerspectiveTool *perspectiveTool = dynamic_cast<PerspectiveTool *>(
TTool::getTool("T_PerspectiveGrid", TTool::RasterImage));
std::vector<PerspectiveObject *> perspectiveObjs =
perspectiveTool->getPerspectiveObjects();
TPointD pointToUse = TPointD(0.0, 0.0);
TPointD dpiScale = getViewer()->getDpiScale();
TPointD refPoint = m_firstPoint;
refPoint.x *= dpiScale.x;
refPoint.y *= dpiScale.y;
if (e.isAltPressed() || m_perspectiveIndex < 0) {
// let's get info about our current location // let's get info about our current location
double denominator = m_lastPoint.x - m_firstPoint.x; double denominator = m_lastPoint.x - m_firstPoint.x;
double numerator = m_lastPoint.y - m_firstPoint.y; double numerator = m_lastPoint.y - m_firstPoint.y;
@ -415,140 +436,134 @@ void FullColorBrushTool::leftButtonDrag(const TPointD &pos,
// now let's get the angle of each of the assistant points // now let's get the angle of each of the assistant points
std::vector<double> anglesToAssistants; std::vector<double> anglesToAssistants;
TPointD pointToUse = TPointD(0.0, 0.0); for (auto data : perspectiveObjs) {
TPointD point = data->getReferencePoint(refPoint);
PerspectiveTool *perspectiveTool = dynamic_cast<PerspectiveTool *>( point.x /= dpiScale.x;
TTool::getTool("T_PerspectiveGrid", TTool::RasterImage)); point.y /= dpiScale.y;
if (perspectiveTool) { double newDenominator = point.x - m_firstPoint.x;
TPointD dpiScale = getViewer()->getDpiScale(); double newNumerator = point.y - m_firstPoint.y;
TPointD refPoint = m_firstPoint; if (areAlmostEqual(newDenominator, 0.0, 0.0001)) {
refPoint.x *= dpiScale.x; newDenominator = newDenominator < 0 ? -0.0001 : 0.0001;
refPoint.y *= dpiScale.y; }
if (areAlmostEqual(newNumerator, 0.0, 0.0001)) {
std::vector<PerspectiveObject *> perspectiveObjs = newNumerator = newNumerator < 0 ? -0.0001 : 0.0001;
perspectiveTool->getPerspectiveObjects();
for (auto data : perspectiveObjs) {
TPointD point = data->getReferencePoint(refPoint);
point.x /= dpiScale.x;
point.y /= dpiScale.y;
double newDenominator = point.x - m_firstPoint.x;
double newNumerator = point.y - m_firstPoint.y;
if (areAlmostEqual(newDenominator, 0.0, 0.0001)) {
newDenominator = newDenominator < 0 ? -0.0001 : 0.0001;
}
if (areAlmostEqual(newNumerator, 0.0, 0.0001)) {
newNumerator = newNumerator < 0 ? -0.0001 : 0.0001;
}
double newSlope = (newNumerator / newDenominator);
double newAngle = std::atan(newSlope) * (180 / 3.14159);
anglesToAssistants.push_back(newAngle);
} }
// figure out which angle is closer double newSlope = (newNumerator / newDenominator);
double difference = 360; double newAngle = std::atan(newSlope) * (180 / 3.14159);
anglesToAssistants.push_back(newAngle);
for (int i = 0; i < anglesToAssistants.size(); i++) {
double newDifference = abs(angle - anglesToAssistants.at(i));
if (newDifference < difference ||
(180 - newDifference) < difference) {
difference = std::min(newDifference, (180 - newDifference));
pointToUse = perspectiveObjs.at(i)->getReferencePoint(refPoint);
pointToUse.x /= dpiScale.x;
pointToUse.y /= dpiScale.y;
}
}
} }
double distanceFirstToLast = // figure out which angle is closer
std::sqrt(std::pow((m_lastPoint.x - m_firstPoint.x), 2) + double difference = 360;
std::pow((m_lastPoint.y - m_firstPoint.y), 2));
double distanceLastToAssistant =
std::sqrt(std::pow((pointToUse.x - m_lastPoint.x), 2) +
std::pow((pointToUse.y - m_lastPoint.y), 2));
double distanceFirstToAssistant =
std::sqrt(std::pow((pointToUse.x - m_firstPoint.x), 2) +
std::pow((pointToUse.y - m_firstPoint.y), 2));
if (distanceFirstToAssistant == 0.0) distanceFirstToAssistant = 0.001; for (int i = 0; i < anglesToAssistants.size(); i++) {
double newDifference = abs(angle - anglesToAssistants.at(i));
double ratio = distanceFirstToLast / distanceFirstToAssistant; if (newDifference < difference || (180 - newDifference) < difference) {
difference = std::min(newDifference, (180 - newDifference));
double newX; pointToUse = perspectiveObjs.at(i)->getReferencePoint(refPoint);
double newY; pointToUse.x /= dpiScale.x;
pointToUse.y /= dpiScale.y;
// flip the direction if the last point is farther than the first point m_perspectiveIndex = i;
if (distanceFirstToAssistant < distanceLastToAssistant &&
distanceFirstToLast < distanceLastToAssistant) {
newX = ((1 + ratio) * m_firstPoint.x) - (ratio * pointToUse.x);
newY = ((1 + ratio) * m_firstPoint.y) - (ratio * pointToUse.y);
} else {
newX = ((1 - ratio) * m_firstPoint.x) + (ratio * pointToUse.x);
newY = ((1 - ratio) * m_firstPoint.y) + (ratio * pointToUse.y);
}
m_lastPoint = TPointD(newX, newY);
invalidateRect += TRectD(m_firstPoint, m_lastPoint).enlarge(2);
} else if (e.isCtrlPressed()) {
double distance = (m_brushPos.x - m_maxCursorThick + 1) * 0.5;
TRectD brushRect =
TRectD(TPointD(m_brushPos.x - distance, m_brushPos.y - distance),
TPointD(m_brushPos.x + distance, m_brushPos.y + distance));
invalidateRect += (brushRect);
double denominator = m_lastPoint.x - m_firstPoint.x;
if (denominator == 0) denominator == 0.001;
double slope = ((m_lastPoint.y - m_firstPoint.y) / denominator);
double radAngle = std::atan(abs(slope));
double angle = radAngle * (180 / 3.14159);
if (abs(angle) >= 82.5)
m_lastPoint.x = m_firstPoint.x;
else if (abs(angle) < 7.5)
m_lastPoint.y = m_firstPoint.y;
else {
double xDistance = m_lastPoint.x - m_firstPoint.x;
double yDistance = m_lastPoint.y - m_firstPoint.y;
double totalDistance =
std::sqrt(std::pow(xDistance, 2) + std::pow(yDistance, 2));
double xLength = 0.0;
double yLength = 0.0;
if (angle >= 7.5 && angle < 22.5) {
yLength = std::sin(15 * (3.14159 / 180)) * totalDistance;
xLength = std::cos(15 * (3.14159 / 180)) * totalDistance;
} else if (angle >= 22.5 && angle < 37.5) {
yLength = std::sin(30 * (3.14159 / 180)) * totalDistance;
xLength = std::cos(30 * (3.14159 / 180)) * totalDistance;
} else if (angle >= 37.5 && angle < 52.5) {
yLength = std::sin(45 * (3.14159 / 180)) * totalDistance;
xLength = std::cos(45 * (3.14159 / 180)) * totalDistance;
} else if (angle >= 52.5 && angle < 67.5) {
yLength = std::sin(60 * (3.14159 / 180)) * totalDistance;
xLength = std::cos(60 * (3.14159 / 180)) * totalDistance;
} else if (angle >= 67.5 && angle < 82.5) {
yLength = std::sin(75 * (3.14159 / 180)) * totalDistance;
xLength = std::cos(75 * (3.14159 / 180)) * totalDistance;
}
if (yDistance == abs(yDistance)) {
m_lastPoint.y = m_firstPoint.y + yLength;
} else {
m_lastPoint.y = m_firstPoint.y - yLength;
}
if (xDistance == abs(xDistance)) {
m_lastPoint.x = m_firstPoint.x + xLength;
} else {
m_lastPoint.x = m_firstPoint.x - xLength;
} }
} }
} else {
pointToUse =
perspectiveObjs.at(m_perspectiveIndex)->getReferencePoint(refPoint);
pointToUse.x /= dpiScale.x;
pointToUse.y /= dpiScale.y;
} }
// keep this here for possible eventual variable width double distanceFirstToLast =
// if (getApplication()->getCurrentLevelStyle()->getTagId() == std::sqrt(std::pow((m_lastPoint.x - m_firstPoint.x), 2) +
// 4001) // mypaint brush case std::pow((m_lastPoint.y - m_firstPoint.y), 2));
// m_oldPressure = m_enabledPressure && e.isTablet() ? e.m_pressure : 0.5; double distanceLastToAssistant =
// else std::sqrt(std::pow((pointToUse.x - m_lastPoint.x), 2) +
// m_oldPressure = m_enabledPressure ? e.m_pressure : 1.0; std::pow((pointToUse.y - m_lastPoint.y), 2));
double distanceFirstToAssistant =
std::sqrt(std::pow((pointToUse.x - m_firstPoint.x), 2) +
std::pow((pointToUse.y - m_firstPoint.y), 2));
if (distanceFirstToAssistant == 0.0) distanceFirstToAssistant = 0.001;
double ratio = distanceFirstToLast / distanceFirstToAssistant;
double newX;
double newY;
// flip the direction if the last point is farther than the first point
if (distanceFirstToAssistant < distanceLastToAssistant &&
distanceFirstToLast < distanceLastToAssistant) {
newX = ((1 + ratio) * m_firstPoint.x) - (ratio * pointToUse.x);
newY = ((1 + ratio) * m_firstPoint.y) - (ratio * pointToUse.y);
} else {
newX = ((1 - ratio) * m_firstPoint.x) + (ratio * pointToUse.x);
newY = ((1 - ratio) * m_firstPoint.y) + (ratio * pointToUse.y);
}
usePos = m_lastPoint = TPointD(newX, newY);
invalidateRect += TRectD(m_firstPoint, m_lastPoint).enlarge(2);
} else if (e.isCtrlPressed()) {
double distance = (m_brushPos.x - m_maxCursorThick + 1) * 0.5;
TRectD brushRect =
TRectD(TPointD(m_brushPos.x - distance, m_brushPos.y - distance),
TPointD(m_brushPos.x + distance, m_brushPos.y + distance));
invalidateRect += (brushRect);
double denominator = m_lastPoint.x - m_firstPoint.x;
if (denominator == 0) denominator == 0.001;
double slope = ((m_lastPoint.y - m_firstPoint.y) / denominator);
double radAngle = std::atan(abs(slope));
double angle = radAngle * (180 / 3.14159);
if (abs(angle) >= 82.5)
m_lastPoint.x = m_firstPoint.x;
else if (abs(angle) < 7.5)
m_lastPoint.y = m_firstPoint.y;
else {
double xDistance = m_lastPoint.x - m_firstPoint.x;
double yDistance = m_lastPoint.y - m_firstPoint.y;
double totalDistance =
std::sqrt(std::pow(xDistance, 2) + std::pow(yDistance, 2));
double xLength = 0.0;
double yLength = 0.0;
if (angle >= 7.5 && angle < 22.5) {
yLength = std::sin(15 * (3.14159 / 180)) * totalDistance;
xLength = std::cos(15 * (3.14159 / 180)) * totalDistance;
} else if (angle >= 22.5 && angle < 37.5) {
yLength = std::sin(30 * (3.14159 / 180)) * totalDistance;
xLength = std::cos(30 * (3.14159 / 180)) * totalDistance;
} else if (angle >= 37.5 && angle < 52.5) {
yLength = std::sin(45 * (3.14159 / 180)) * totalDistance;
xLength = std::cos(45 * (3.14159 / 180)) * totalDistance;
} else if (angle >= 52.5 && angle < 67.5) {
yLength = std::sin(60 * (3.14159 / 180)) * totalDistance;
xLength = std::cos(60 * (3.14159 / 180)) * totalDistance;
} else if (angle >= 67.5 && angle < 82.5) {
yLength = std::sin(75 * (3.14159 / 180)) * totalDistance;
xLength = std::cos(75 * (3.14159 / 180)) * totalDistance;
}
if (yDistance == abs(yDistance)) {
m_lastPoint.y = m_firstPoint.y + yLength;
} else {
m_lastPoint.y = m_firstPoint.y - yLength;
}
if (xDistance == abs(xDistance)) {
m_lastPoint.x = m_firstPoint.x + xLength;
} else {
m_lastPoint.x = m_firstPoint.x - xLength;
}
}
}
// keep this here for possible eventual variable width
// if (getApplication()->getCurrentLevelStyle()->getTagId() ==
// 4001) // mypaint brush case
// m_oldPressure = m_enabledPressure && e.isTablet() ? e.m_pressure : 0.5;
// else
// m_oldPressure = m_enabledPressure ? e.m_pressure : 1.0;
if (m_isStraight) {
m_mousePos = pos; m_mousePos = pos;
m_brushPos = pos; m_brushPos = pos;
invalidate(invalidateRect); invalidate(invalidateRect);
@ -565,7 +580,7 @@ void FullColorBrushTool::leftButtonDrag(const TPointD &pos,
TRasterP ras = ri->getRaster(); TRasterP ras = ri->getRaster();
TPointD rasCenter = ras->getCenterD(); TPointD rasCenter = ras->getCenterD();
TPointD point(pos + rasCenter); TPointD point(usePos + rasCenter);
double pressure; double pressure;
if (getApplication()->getCurrentLevelStyle()->getTagId() == if (getApplication()->getCurrentLevelStyle()->getTagId() ==
4001) // mypaint brush case 4001) // mypaint brush case
@ -602,7 +617,7 @@ void FullColorBrushTool::leftButtonUp(const TPointD &pos,
TRasterP ras = ri->getRaster(); TRasterP ras = ri->getRaster();
TPointD rasCenter = ras->getCenterD(); TPointD rasCenter = ras->getCenterD();
TPointD point; TPointD point;
if (e.isCtrlPressed() || m_snapAssistant || e.isAltPressed()) if (e.isCtrlPressed() || m_snapGrid.getValue() || e.isAltPressed())
point = TPointD(m_lastPoint + rasCenter); point = TPointD(m_lastPoint + rasCenter);
else else
point = TPointD(pos + rasCenter); point = TPointD(pos + rasCenter);
@ -655,8 +670,8 @@ void FullColorBrushTool::leftButtonUp(const TPointD &pos,
m_strokeRect.empty(); m_strokeRect.empty();
m_mousePressed = false; m_mousePressed = false;
m_isStraight = false; m_isStraight = false;
m_snapAssistant = false;
m_oldPressure = -1.0; m_oldPressure = -1.0;
m_perspectiveIndex = -1;
} }
//--------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------
@ -838,6 +853,7 @@ bool FullColorBrushTool::onPropertyChanged(std::string propertyName) {
FullcolorModifierOpacity = m_modifierOpacity.getValue(); FullcolorModifierOpacity = m_modifierOpacity.getValue();
FullcolorModifierEraser = m_modifierEraser.getValue() ? 1 : 0; FullcolorModifierEraser = m_modifierEraser.getValue() ? 1 : 0;
FullcolorModifierLockAlpha = m_modifierLockAlpha.getValue() ? 1 : 0; FullcolorModifierLockAlpha = m_modifierLockAlpha.getValue() ? 1 : 0;
FullcolorBrushSnapGrid = m_snapGrid.getValue() ? 1 : 0;
if (m_preset.getValue() != CUSTOM_WSTR) { if (m_preset.getValue() != CUSTOM_WSTR) {
m_preset.setValue(CUSTOM_WSTR); m_preset.setValue(CUSTOM_WSTR);
@ -952,6 +968,7 @@ void FullColorBrushTool::loadLastBrush() {
m_modifierOpacity.setValue(FullcolorModifierOpacity); m_modifierOpacity.setValue(FullcolorModifierOpacity);
m_modifierEraser.setValue(FullcolorModifierEraser ? true : false); m_modifierEraser.setValue(FullcolorModifierEraser ? true : false);
m_modifierLockAlpha.setValue(FullcolorModifierLockAlpha ? true : false); m_modifierLockAlpha.setValue(FullcolorModifierLockAlpha ? true : false);
m_snapGrid.setValue(FullcolorBrushSnapGrid ? true : false);
} }
//------------------------------------------------------------------ //------------------------------------------------------------------

View file

@ -95,6 +95,7 @@ protected:
TBoolProperty m_modifierEraser; TBoolProperty m_modifierEraser;
TBoolProperty m_modifierLockAlpha; TBoolProperty m_modifierLockAlpha;
TEnumProperty m_preset; TEnumProperty m_preset;
TBoolProperty m_snapGrid;
TPixel32 m_currentColor; TPixel32 m_currentColor;
bool m_enabledPressure; bool m_enabledPressure;
@ -126,10 +127,11 @@ protected:
bool m_isStraight = false; bool m_isStraight = false;
TPointD m_firstPoint; TPointD m_firstPoint;
TPointD m_lastPoint; TPointD m_lastPoint;
bool m_snapAssistant = false;
double m_oldPressure = -1.0; double m_oldPressure = -1.0;
bool m_propertyUpdating = false; bool m_propertyUpdating = false;
int m_perspectiveIndex = -1;
}; };
//------------------------------------------------------------ //------------------------------------------------------------

View file

@ -2114,7 +2114,7 @@ void BrushToolOptionsBox::filterControls() {
it != m_labels.end(); it++) { it != m_labels.end(); it++) {
bool isModifier = (it.key().substr(0, 8) == "Modifier"); bool isModifier = (it.key().substr(0, 8) == "Modifier");
bool isCommon = (it.key() == "Lock Alpha" || it.key() == "Pressure" || bool isCommon = (it.key() == "Lock Alpha" || it.key() == "Pressure" ||
it.key() == "Preset:"); it.key() == "Preset:" || it.key() == "Grid");
bool visible = isCommon || (isModifier == showModifiers); bool visible = isCommon || (isModifier == showModifiers);
it.value()->setVisible(visible); it.value()->setVisible(visible);
} }
@ -2123,7 +2123,7 @@ void BrushToolOptionsBox::filterControls() {
it != m_controls.end(); it++) { it != m_controls.end(); it++) {
bool isModifier = (it.key().substr(0, 8) == "Modifier"); bool isModifier = (it.key().substr(0, 8) == "Modifier");
bool isCommon = (it.key() == "Lock Alpha" || it.key() == "Pressure" || bool isCommon = (it.key() == "Lock Alpha" || it.key() == "Pressure" ||
it.key() == "Preset:"); it.key() == "Preset:" || it.key() == "Grid");
bool visible = isCommon || (isModifier == showModifiers); bool visible = isCommon || (isModifier == showModifiers);
if (QWidget *widget = dynamic_cast<QWidget *>(it.value())) if (QWidget *widget = dynamic_cast<QWidget *>(it.value()))
widget->setVisible(visible); widget->setVisible(visible);

View file

@ -61,6 +61,7 @@ TEnv::DoubleVar RasterBrushHardness("RasterBrushHardness", 100);
TEnv::DoubleVar RasterBrushModifierSize("RasterBrushModifierSize", 0); TEnv::DoubleVar RasterBrushModifierSize("RasterBrushModifierSize", 0);
TEnv::StringVar RasterBrushPreset("RasterBrushPreset", "<custom>"); TEnv::StringVar RasterBrushPreset("RasterBrushPreset", "<custom>");
TEnv::IntVar BrushLockAlpha("InknpaintBrushLockAlpha", 0); TEnv::IntVar BrushLockAlpha("InknpaintBrushLockAlpha", 0);
TEnv::IntVar BrushSnapGrid("InknpaintBrushSnapGrid", 0);
//------------------------------------------------------------------- //-------------------------------------------------------------------
#define CUSTOM_WSTR L"<custom>" #define CUSTOM_WSTR L"<custom>"
@ -890,7 +891,8 @@ ToonzRasterBrushTool::ToonzRasterBrushTool(std::string name, int targetType)
, m_targetType(targetType) , m_targetType(targetType)
, m_workingFrameId(TFrameId()) , m_workingFrameId(TFrameId())
, m_notifier(0) , m_notifier(0)
, m_modifierLockAlpha("Lock Alpha", false) { , m_modifierLockAlpha("Lock Alpha", false)
, m_snapGrid("Grid", false) {
bind(targetType); bind(targetType);
m_rasThickness.setNonLinearSlider(); m_rasThickness.setNonLinearSlider();
@ -911,6 +913,9 @@ ToonzRasterBrushTool::ToonzRasterBrushTool(std::string name, int targetType)
m_prop[0].bind(m_pressure); m_prop[0].bind(m_pressure);
m_prop[0].bind(m_snapGrid);
m_snapGrid.setId("SnapGrid");
m_prop[0].bind(m_preset); m_prop[0].bind(m_preset);
m_preset.setId("BrushPreset"); m_preset.setId("BrushPreset");
m_preset.addValue(CUSTOM_WSTR); m_preset.addValue(CUSTOM_WSTR);
@ -1110,6 +1115,7 @@ void ToonzRasterBrushTool::updateTranslation() {
m_pencil.setQStringName(tr("Pencil")); m_pencil.setQStringName(tr("Pencil"));
m_pressure.setQStringName(tr("Pressure")); m_pressure.setQStringName(tr("Pressure"));
m_modifierLockAlpha.setQStringName(tr("Lock Alpha")); m_modifierLockAlpha.setQStringName(tr("Lock Alpha"));
m_snapGrid.setQStringName(tr("Grid"));
} }
//--------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------
@ -1301,12 +1307,16 @@ void ToonzRasterBrushTool::leftButtonDown(const TPointD &pos,
} }
if (e.isAltPressed()) { if (e.isAltPressed()) {
m_snapAssistant = true;
m_isStraight = true; m_isStraight = true;
m_firstPoint = pos; m_firstPoint = pos;
m_lastPoint = pos; m_lastPoint = pos;
} }
if (m_snapGrid.getValue()) {
m_firstPoint = pos;
m_lastPoint = pos;
}
// assert(0<=m_styleId && m_styleId<2); // assert(0<=m_styleId && m_styleId<2);
TImageP img = getImage(true); TImageP img = getImage(true);
TToonzImageP ri(img); TToonzImageP ri(img);
@ -1442,6 +1452,7 @@ void ToonzRasterBrushTool::leftButtonDown(const TPointD &pos,
// updating m_brushPos is needed to refresh viewer properly // updating m_brushPos is needed to refresh viewer properly
m_mousePos = pos; m_mousePos = pos;
m_brushPos = getCenteredCursorPos(pos); m_brushPos = getCenteredCursorPos(pos);
m_perspectiveIndex = -1;
} }
//------------------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------------
@ -1455,16 +1466,27 @@ void ToonzRasterBrushTool::leftButtonDrag(const TPointD &pos,
} }
TRectD invalidateRect; TRectD invalidateRect;
if (m_isStraight) { invalidateRect = TRectD(m_firstPoint, m_lastPoint).enlarge(2);
invalidateRect = TRectD(m_firstPoint, m_lastPoint).enlarge(2); m_lastPoint = pos;
m_lastPoint = pos; TPointD usePos = pos;
if (e.isAltPressed()) {
double distance = (m_brushPos.x - m_maxCursorThick + 1) * 0.5;
TRectD brushRect =
TRectD(TPointD(m_brushPos.x - distance, m_brushPos.y - distance),
TPointD(m_brushPos.x + distance, m_brushPos.y + distance));
invalidateRect += (brushRect);
if (e.isAltPressed() || m_snapGrid.getValue()) {
double distance = (m_brushPos.x - m_maxCursorThick + 1) * 0.5;
TRectD brushRect =
TRectD(TPointD(m_brushPos.x - distance, m_brushPos.y - distance),
TPointD(m_brushPos.x + distance, m_brushPos.y + distance));
invalidateRect += (brushRect);
PerspectiveTool *perspectiveTool = dynamic_cast<PerspectiveTool *>(
TTool::getTool("T_PerspectiveGrid", TTool::ToonzImage));
std::vector<PerspectiveObject *> perspectiveObjs =
perspectiveTool->getPerspectiveObjects();
TPointD pointToUse = TPointD(0.0, 0.0);
TPointD dpiScale = getViewer()->getDpiScale();
TPointD refPoint = m_firstPoint;
refPoint.x *= dpiScale.x;
refPoint.y *= dpiScale.y;
if (e.isAltPressed() || m_perspectiveIndex < 0) {
// let's get info about our current location // let's get info about our current location
double denominator = m_lastPoint.x - m_firstPoint.x; double denominator = m_lastPoint.x - m_firstPoint.x;
double numerator = m_lastPoint.y - m_firstPoint.y; double numerator = m_lastPoint.y - m_firstPoint.y;
@ -1479,210 +1501,201 @@ void ToonzRasterBrushTool::leftButtonDrag(const TPointD &pos,
// now let's get the angle of each of the assistant points // now let's get the angle of each of the assistant points
std::vector<double> anglesToAssistants; std::vector<double> anglesToAssistants;
TPointD pointToUse = TPointD(0.0, 0.0);
PerspectiveTool *perspectiveTool = dynamic_cast<PerspectiveTool *>( for (auto data : perspectiveObjs) {
TTool::getTool("T_PerspectiveGrid", TTool::ToonzImage)); TPointD point = data->getReferencePoint(refPoint);
if (perspectiveTool) { point.x /= dpiScale.x;
TPointD dpiScale = getViewer()->getDpiScale(); point.y /= dpiScale.y;
TPointD refPoint = m_firstPoint; double newDenominator = point.x - m_firstPoint.x;
refPoint.x *= dpiScale.x; double newNumerator = point.y - m_firstPoint.y;
refPoint.y *= dpiScale.y; if (areAlmostEqual(newDenominator, 0.0, 0.0001)) {
newDenominator = newDenominator < 0 ? -0.0001 : 0.0001;
std::vector<PerspectiveObject *> perspectiveObjs = }
perspectiveTool->getPerspectiveObjects(); if (areAlmostEqual(newNumerator, 0.0, 0.0001)) {
for (auto data : perspectiveObjs) { newNumerator = newNumerator < 0 ? -0.0001 : 0.0001;
TPointD point = data->getReferencePoint(refPoint);
point.x /= dpiScale.x;
point.y /= dpiScale.y;
double newDenominator = point.x - m_firstPoint.x;
double newNumerator = point.y - m_firstPoint.y;
if (areAlmostEqual(newDenominator, 0.0, 0.0001)) {
newDenominator = newDenominator < 0 ? -0.0001 : 0.0001;
}
if (areAlmostEqual(newNumerator, 0.0, 0.0001)) {
newNumerator = newNumerator < 0 ? -0.0001 : 0.0001;
}
double newSlope = (newNumerator / newDenominator);
double newAngle = std::atan(newSlope) * (180 / 3.14159);
anglesToAssistants.push_back(newAngle);
} }
// figure out which angle is closer double newSlope = (newNumerator / newDenominator);
double difference = 360; double newAngle = std::atan(newSlope) * (180 / 3.14159);
anglesToAssistants.push_back(newAngle);
for (int i = 0; i < anglesToAssistants.size(); i++) {
double newDifference = abs(angle - anglesToAssistants.at(i));
if (newDifference < difference ||
(180 - newDifference) < difference) {
difference = std::min(newDifference, (180 - newDifference));
pointToUse = perspectiveObjs.at(i)->getReferencePoint(refPoint);
pointToUse.x /= dpiScale.x;
pointToUse.y /= dpiScale.y;
}
}
} }
double distanceFirstToLast = // figure out which angle is closer
std::sqrt(std::pow((m_lastPoint.x - m_firstPoint.x), 2) + double difference = 360;
std::pow((m_lastPoint.y - m_firstPoint.y), 2));
double distanceLastToAssistant =
std::sqrt(std::pow((pointToUse.x - m_lastPoint.x), 2) +
std::pow((pointToUse.y - m_lastPoint.y), 2));
double distanceFirstToAssistant =
std::sqrt(std::pow((pointToUse.x - m_firstPoint.x), 2) +
std::pow((pointToUse.y - m_firstPoint.y), 2));
if (distanceFirstToAssistant == 0.0) distanceFirstToAssistant = 0.001; for (int i = 0; i < anglesToAssistants.size(); i++) {
double newDifference = abs(angle - anglesToAssistants.at(i));
double ratio = distanceFirstToLast / distanceFirstToAssistant; if (newDifference < difference || (180 - newDifference) < difference) {
difference = std::min(newDifference, (180 - newDifference));
double newX; pointToUse = perspectiveObjs.at(i)->getReferencePoint(refPoint);
double newY; pointToUse.x /= dpiScale.x;
pointToUse.y /= dpiScale.y;
// flip the direction if the last point is farther than the first point m_perspectiveIndex = i;
if (distanceFirstToAssistant < distanceLastToAssistant &&
distanceFirstToLast < distanceLastToAssistant) {
newX = ((1 + ratio) * m_firstPoint.x) - (ratio * pointToUse.x);
newY = ((1 + ratio) * m_firstPoint.y) - (ratio * pointToUse.y);
} else {
newX = ((1 - ratio) * m_firstPoint.x) + (ratio * pointToUse.x);
newY = ((1 - ratio) * m_firstPoint.y) + (ratio * pointToUse.y);
}
m_lastPoint = TPointD(newX, newY);
invalidateRect += TRectD(m_firstPoint, m_lastPoint).enlarge(2);
} else if (e.isCtrlPressed()) {
double distance = (m_brushPos.x - m_maxCursorThick + 1) * 0.5;
TRectD brushRect =
TRectD(TPointD(m_brushPos.x - distance, m_brushPos.y - distance),
TPointD(m_brushPos.x + distance, m_brushPos.y + distance));
invalidateRect += (brushRect);
double denominator = m_lastPoint.x - m_firstPoint.x;
if (denominator == 0) denominator == 0.001;
double slope = ((m_lastPoint.y - m_firstPoint.y) / denominator);
double radAngle = std::atan(abs(slope));
double angle = radAngle * (180 / 3.14159);
if (abs(angle) >= 82.5) {
// make it vertical
m_lastPoint.x = m_firstPoint.x;
} else if (abs(angle) < 7.5) {
// make it horizontal
m_lastPoint.y = m_firstPoint.y;
} else {
double xDistance = m_lastPoint.x - m_firstPoint.x;
double yDistance = m_lastPoint.y - m_firstPoint.y;
double totalDistance =
std::sqrt(std::pow(xDistance, 2) + std::pow(yDistance, 2));
double xLength = 0.0;
double yLength = 0.0;
if (angle >= 7.5 && angle < 22.5) {
yLength = std::sin(15 * (3.14159 / 180)) * totalDistance;
xLength = std::cos(15 * (3.14159 / 180)) * totalDistance;
} else if (angle >= 22.5 && angle < 37.5) {
yLength = std::sin(30 * (3.14159 / 180)) * totalDistance;
xLength = std::cos(30 * (3.14159 / 180)) * totalDistance;
} else if (angle >= 37.5 && angle < 52.5) {
yLength = std::sin(45 * (3.14159 / 180)) * totalDistance;
xLength = std::cos(45 * (3.14159 / 180)) * totalDistance;
} else if (angle >= 52.5 && angle < 67.5) {
yLength = std::sin(60 * (3.14159 / 180)) * totalDistance;
xLength = std::cos(60 * (3.14159 / 180)) * totalDistance;
} else if (angle >= 67.5 && angle < 82.5) {
yLength = std::sin(75 * (3.14159 / 180)) * totalDistance;
xLength = std::cos(75 * (3.14159 / 180)) * totalDistance;
}
if (yDistance == abs(yDistance)) {
m_lastPoint.y = m_firstPoint.y + yLength;
} else {
m_lastPoint.y = m_firstPoint.y - yLength;
}
if (xDistance == abs(xDistance)) {
m_lastPoint.x = m_firstPoint.x + xLength;
} else {
m_lastPoint.x = m_firstPoint.x - xLength;
} }
} }
} else {
pointToUse =
perspectiveObjs.at(m_perspectiveIndex)->getReferencePoint(refPoint);
pointToUse.x /= dpiScale.x;
pointToUse.y /= dpiScale.y;
} }
int maxThickness = m_rasThickness.getValue().second; double distanceFirstToLast =
double thickness = (m_pressure.getValue()) std::sqrt(std::pow((m_lastPoint.x - m_firstPoint.x), 2) +
? computeThickness(e.m_pressure, m_rasThickness) * 2 std::pow((m_lastPoint.y - m_firstPoint.y), 2));
: maxThickness; double distanceLastToAssistant =
// if (m_dragCount < 3 && !m_isMyPaintStyleSelected && thickness > 0.0) { std::sqrt(std::pow((pointToUse.x - m_lastPoint.x), 2) +
// if (m_hardness.getValue() == 100 || m_pencil.getValue()) { std::pow((pointToUse.y - m_lastPoint.y), 2));
// std::vector<TThickPoint> sequence = double distanceFirstToAssistant =
// m_rasterTrack->getPointsSequence(); std::sqrt(std::pow((pointToUse.x - m_firstPoint.x), 2) +
// if (sequence.size() > 0) sequence[0].thick = thickness; std::pow((pointToUse.y - m_firstPoint.y), 2));
// m_rasterTrack->setPointsSequence(sequence);
// } else if (m_points.size() > 0) {
// m_points[0].thick == thickness;
// // below is code to allow variable thickess
// // but it causes artifacting at the start of the stroke.
// TToonzImageP ti = TImageP(getImage(true));
// TPointD rasCenter = ti->getRaster()->getCenterD();
// TThickPoint point(getCenteredCursorPos(m_firstPoint) + rasCenter,
// thickness);
// m_points.push_back(point);
// m_bluredBrush->addPoint(point, 1);
// DrawOrder drawOrder = (DrawOrder)m_drawOrder.getIndex();
// TImageP img = getImage(true); if (distanceFirstToAssistant == 0.0) distanceFirstToAssistant = 0.001;
// TToonzImageP ri(img);
// m_strokeRect = m_bluredBrush->getBoundFromPoints(m_points);
// updateWorkAndBackupRasters(m_strokeRect);
// m_tileSaver->save(m_strokeRect);
// m_bluredBrush->updateDrawing(ri->getRaster(), m_backupRas,
// m_strokeRect,
// m_styleId, drawOrder);
// m_points.erase(m_points.begin());
// }
//}
// if (m_dragCount < 3 && m_isMyPaintStyleSelected) { double ratio = distanceFirstToLast / distanceFirstToAssistant;
// TToonzImageP ti = TImageP(getImage(true));
// TRasterP ras = ti->getRaster();
// TPointD rasCenter = ti->getRaster()->getCenterD();
// TPointD point(getCenteredCursorPos(m_firstPoint) + rasCenter);
// double pressure =
// m_pressure.getValue() && e.isTablet() ? e.m_pressure : 0.5;
// m_strokeSegmentRect.empty(); double newX;
// m_toonz_brush->strokeTo(point, pressure, restartBrushTimer()); double newY;
// TRect updateRect = m_strokeSegmentRect * ras->getBounds();
// if (!updateRect.isEmpty()) {
// m_toonz_brush->updateDrawing(ras, m_backupRas, m_strokeSegmentRect,
// m_styleId);
// }
// m_lastRect = m_strokeRect;
// TPointD thickOffset(m_maxCursorThick * 0.5, m_maxCursorThick * 0.5); // flip the direction if the last point is farther than the first point
// invalidateRect = convert(m_strokeSegmentRect) - rasCenter; if (distanceFirstToAssistant < distanceLastToAssistant &&
// invalidateRect += distanceFirstToLast < distanceLastToAssistant) {
// TRectD(getCenteredCursorPos(m_firstPoint) - thickOffset, newX = ((1 + ratio) * m_firstPoint.x) - (ratio * pointToUse.x);
// getCenteredCursorPos(m_firstPoint) + thickOffset); newY = ((1 + ratio) * m_firstPoint.y) - (ratio * pointToUse.y);
// invalidateRect += } else {
// TRectD(m_brushPos - thickOffset, m_brushPos + thickOffset); newX = ((1 - ratio) * m_firstPoint.x) + (ratio * pointToUse.x);
//} newY = ((1 - ratio) * m_firstPoint.y) + (ratio * pointToUse.y);
}
// m_oldThickness = thickness; usePos = m_lastPoint = TPointD(newX, newY);
// double pressure = invalidateRect += TRectD(m_firstPoint, m_lastPoint).enlarge(2);
// m_pressure.getValue() && e.isTablet() ? e.m_pressure : 0.5; } else if (e.isCtrlPressed()) {
// m_oldPressure = pressure; double distance = (m_brushPos.x - m_maxCursorThick + 1) * 0.5;
TRectD brushRect =
TRectD(TPointD(m_brushPos.x - distance, m_brushPos.y - distance),
TPointD(m_brushPos.x + distance, m_brushPos.y + distance));
invalidateRect += (brushRect);
// m_dragCount++; double denominator = m_lastPoint.x - m_firstPoint.x;
if (denominator == 0) denominator == 0.001;
double slope = ((m_lastPoint.y - m_firstPoint.y) / denominator);
double radAngle = std::atan(abs(slope));
double angle = radAngle * (180 / 3.14159);
if (abs(angle) >= 82.5) {
// make it vertical
m_lastPoint.x = m_firstPoint.x;
} else if (abs(angle) < 7.5) {
// make it horizontal
m_lastPoint.y = m_firstPoint.y;
} else {
double xDistance = m_lastPoint.x - m_firstPoint.x;
double yDistance = m_lastPoint.y - m_firstPoint.y;
double totalDistance =
std::sqrt(std::pow(xDistance, 2) + std::pow(yDistance, 2));
double xLength = 0.0;
double yLength = 0.0;
if (angle >= 7.5 && angle < 22.5) {
yLength = std::sin(15 * (3.14159 / 180)) * totalDistance;
xLength = std::cos(15 * (3.14159 / 180)) * totalDistance;
} else if (angle >= 22.5 && angle < 37.5) {
yLength = std::sin(30 * (3.14159 / 180)) * totalDistance;
xLength = std::cos(30 * (3.14159 / 180)) * totalDistance;
} else if (angle >= 37.5 && angle < 52.5) {
yLength = std::sin(45 * (3.14159 / 180)) * totalDistance;
xLength = std::cos(45 * (3.14159 / 180)) * totalDistance;
} else if (angle >= 52.5 && angle < 67.5) {
yLength = std::sin(60 * (3.14159 / 180)) * totalDistance;
xLength = std::cos(60 * (3.14159 / 180)) * totalDistance;
} else if (angle >= 67.5 && angle < 82.5) {
yLength = std::sin(75 * (3.14159 / 180)) * totalDistance;
xLength = std::cos(75 * (3.14159 / 180)) * totalDistance;
}
if (yDistance == abs(yDistance)) {
m_lastPoint.y = m_firstPoint.y + yLength;
} else {
m_lastPoint.y = m_firstPoint.y - yLength;
}
if (xDistance == abs(xDistance)) {
m_lastPoint.x = m_firstPoint.x + xLength;
} else {
m_lastPoint.x = m_firstPoint.x - xLength;
}
}
}
// if (m_dragCount < 3 && !m_isMyPaintStyleSelected && thickness > 0.0) {
// if (m_hardness.getValue() == 100 || m_pencil.getValue()) {
// std::vector<TThickPoint> sequence =
// m_rasterTrack->getPointsSequence();
// if (sequence.size() > 0) sequence[0].thick = thickness;
// m_rasterTrack->setPointsSequence(sequence);
// } else if (m_points.size() > 0) {
// m_points[0].thick == thickness;
// // below is code to allow variable thickess
// // but it causes artifacting at the start of the stroke.
// TToonzImageP ti = TImageP(getImage(true));
// TPointD rasCenter = ti->getRaster()->getCenterD();
// TThickPoint point(getCenteredCursorPos(m_firstPoint) + rasCenter,
// thickness);
// m_points.push_back(point);
// m_bluredBrush->addPoint(point, 1);
// DrawOrder drawOrder = (DrawOrder)m_drawOrder.getIndex();
// TImageP img = getImage(true);
// TToonzImageP ri(img);
// m_strokeRect = m_bluredBrush->getBoundFromPoints(m_points);
// updateWorkAndBackupRasters(m_strokeRect);
// m_tileSaver->save(m_strokeRect);
// m_bluredBrush->updateDrawing(ri->getRaster(), m_backupRas,
// m_strokeRect,
// m_styleId, drawOrder);
// m_points.erase(m_points.begin());
// }
//}
// if (m_dragCount < 3 && m_isMyPaintStyleSelected) {
// TToonzImageP ti = TImageP(getImage(true));
// TRasterP ras = ti->getRaster();
// TPointD rasCenter = ti->getRaster()->getCenterD();
// TPointD point(getCenteredCursorPos(m_firstPoint) + rasCenter);
// double pressure =
// m_pressure.getValue() && e.isTablet() ? e.m_pressure : 0.5;
// m_strokeSegmentRect.empty();
// m_toonz_brush->strokeTo(point, pressure, restartBrushTimer());
// TRect updateRect = m_strokeSegmentRect * ras->getBounds();
// if (!updateRect.isEmpty()) {
// m_toonz_brush->updateDrawing(ras, m_backupRas, m_strokeSegmentRect,
// m_styleId);
// }
// m_lastRect = m_strokeRect;
// TPointD thickOffset(m_maxCursorThick * 0.5, m_maxCursorThick * 0.5);
// invalidateRect = convert(m_strokeSegmentRect) - rasCenter;
// invalidateRect +=
// TRectD(getCenteredCursorPos(m_firstPoint) - thickOffset,
// getCenteredCursorPos(m_firstPoint) + thickOffset);
// invalidateRect +=
// TRectD(m_brushPos - thickOffset, m_brushPos + thickOffset);
//}
// m_oldThickness = thickness;
// double pressure =
// m_pressure.getValue() && e.isTablet() ? e.m_pressure : 0.5;
// m_oldPressure = pressure;
// m_dragCount++;
if (m_isStraight) {
m_mousePos = pos; m_mousePos = pos;
m_brushPos = getCenteredCursorPos(pos); m_brushPos = getCenteredCursorPos(pos);
invalidate(invalidateRect); invalidate(invalidateRect);
return; return;
} }
TPointD centeredPos = getCenteredCursorPos(pos); TPointD centeredPos = getCenteredCursorPos(usePos);
TToonzImageP ti = TImageP(getImage(true)); TToonzImageP ti = TImageP(getImage(true));
TPointD rasCenter = ti->getRaster()->getCenterD(); TPointD rasCenter = ti->getRaster()->getCenterD();
@ -1819,7 +1832,7 @@ void ToonzRasterBrushTool::leftButtonUp(const TPointD &pos,
return; return;
} }
TPointD centeredPos = getCenteredCursorPos(pos); TPointD centeredPos = getCenteredCursorPos(pos);
if (e.isCtrlPressed() || m_snapAssistant || e.isAltPressed()) if (e.isCtrlPressed() || m_snapGrid.getValue() || e.isAltPressed())
centeredPos = getCenteredCursorPos(m_lastPoint); centeredPos = getCenteredCursorPos(m_lastPoint);
double pressure = m_pressure.getValue() && e.isTablet() ? e.m_pressure : 0.5; double pressure = m_pressure.getValue() && e.isTablet() ? e.m_pressure : 0.5;
// if (!e.isTablet()) m_oldThickness = -1.0; // if (!e.isTablet()) m_oldThickness = -1.0;
@ -1828,6 +1841,7 @@ void ToonzRasterBrushTool::leftButtonUp(const TPointD &pos,
finishRasterBrush(centeredPos, pressure); finishRasterBrush(centeredPos, pressure);
int tc = ToonzCheck::instance()->getChecks(); int tc = ToonzCheck::instance()->getChecks();
if (tc & ToonzCheck::eGap || tc & ToonzCheck::eAutoclose) invalidate(); if (tc & ToonzCheck::eGap || tc & ToonzCheck::eAutoclose) invalidate();
m_perspectiveIndex = -1;
} }
//--------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------
@ -2069,7 +2083,6 @@ void ToonzRasterBrushTool::finishRasterBrush(const TPointD &pos,
} }
delete m_tileSaver; delete m_tileSaver;
m_isStraight = false; m_isStraight = false;
m_snapAssistant = false;
m_oldPressure = -1.0; m_oldPressure = -1.0;
// m_oldThickness = -1.0; // m_oldThickness = -1.0;
// m_dragCount = 0; // m_dragCount = 0;
@ -2321,6 +2334,7 @@ bool ToonzRasterBrushTool::onPropertyChanged(std::string propertyName) {
RasterBrushHardness = m_hardness.getValue(); RasterBrushHardness = m_hardness.getValue();
RasterBrushModifierSize = m_modifierSize.getValue(); RasterBrushModifierSize = m_modifierSize.getValue();
BrushLockAlpha = m_modifierLockAlpha.getValue(); BrushLockAlpha = m_modifierLockAlpha.getValue();
BrushSnapGrid = m_snapGrid.getValue();
// Recalculate/reset based on changed settings // Recalculate/reset based on changed settings
if (propertyName == m_rasThickness.getName()) { if (propertyName == m_rasThickness.getName()) {
@ -2459,6 +2473,7 @@ void ToonzRasterBrushTool::loadLastBrush() {
m_smooth.setValue(BrushSmooth); m_smooth.setValue(BrushSmooth);
m_modifierSize.setValue(RasterBrushModifierSize); m_modifierSize.setValue(RasterBrushModifierSize);
m_modifierLockAlpha.setValue(BrushLockAlpha ? 1 : 0); m_modifierLockAlpha.setValue(BrushLockAlpha ? 1 : 0);
m_snapGrid.setValue(BrushSnapGrid ? 1 : 0);
// Recalculate based on prior values // Recalculate based on prior values
m_minThick = m_rasThickness.getValue().first; m_minThick = m_rasThickness.getValue().first;

View file

@ -183,6 +183,7 @@ protected:
TBoolProperty m_pressure; TBoolProperty m_pressure;
TDoubleProperty m_modifierSize; TDoubleProperty m_modifierSize;
TBoolProperty m_modifierLockAlpha; TBoolProperty m_modifierLockAlpha;
TBoolProperty m_snapGrid;
RasterStrokeGenerator *m_rasterTrack; RasterStrokeGenerator *m_rasterTrack;
TTileSetCM32 *m_tileSet; TTileSetCM32 *m_tileSet;
@ -230,13 +231,14 @@ protected:
bool m_propertyUpdating = false; bool m_propertyUpdating = false;
bool m_isStraight = false; bool m_isStraight = false;
bool m_snapAssistant = false;
TPointD m_firstPoint; TPointD m_firstPoint;
TPointD m_lastPoint; TPointD m_lastPoint;
double m_oldPressure = -1.0; double m_oldPressure = -1.0;
// double m_oldThickness = -1.0; // double m_oldThickness = -1.0;
// int m_dragCount = 0; // int m_dragCount = 0;
int m_perspectiveIndex = -1;
protected: protected:
static void drawLine(const TPointD &point, const TPointD &centre, static void drawLine(const TPointD &point, const TPointD &centre,
bool horizontal, bool isDecimal); bool horizontal, bool isDecimal);

View file

@ -71,6 +71,7 @@ TEnv::IntVar V_VectorBrushAutoClose("VectorBrushAutoClose", 0);
TEnv::IntVar V_VectorBrushAutoFill("VectorBrushAutoFill", 0); TEnv::IntVar V_VectorBrushAutoFill("VectorBrushAutoFill", 0);
TEnv::IntVar V_VectorBrushAutoGroup("VectorBrushAutoGroup", 0); TEnv::IntVar V_VectorBrushAutoGroup("VectorBrushAutoGroup", 0);
TEnv::StringVar V_VectorBrushPreset("VectorBrushPreset", "<custom>"); TEnv::StringVar V_VectorBrushPreset("VectorBrushPreset", "<custom>");
TEnv::IntVar V_VectorBrushSnapGrid("VectorBrushSnapGrid", 0);
//------------------------------------------------------------------- //-------------------------------------------------------------------
@ -535,7 +536,8 @@ ToonzVectorBrushTool::ToonzVectorBrushTool(std::string name, int targetType)
, m_autoGroup("Auto Group", false) , m_autoGroup("Auto Group", false)
, m_autoFill("Auto Fill", false) , m_autoFill("Auto Fill", false)
, m_targetType(targetType) , m_targetType(targetType)
, m_workingFrameId(TFrameId()) { , m_workingFrameId(TFrameId())
, m_snapGrid("Grid", false) {
bind(targetType); bind(targetType);
m_thickness.setNonLinearSlider(); m_thickness.setNonLinearSlider();
@ -572,6 +574,8 @@ ToonzVectorBrushTool::ToonzVectorBrushTool(std::string name, int targetType)
m_snapSensitivity.addValue(MEDIUM_WSTR); m_snapSensitivity.addValue(MEDIUM_WSTR);
m_snapSensitivity.addValue(HIGH_WSTR); m_snapSensitivity.addValue(HIGH_WSTR);
m_prop[0].bind(m_snapGrid);
m_prop[0].bind(m_preset); m_prop[0].bind(m_preset);
m_preset.addValue(CUSTOM_WSTR); m_preset.addValue(CUSTOM_WSTR);
@ -597,6 +601,7 @@ ToonzVectorBrushTool::ToonzVectorBrushTool(std::string name, int targetType)
m_capStyle.setId("Cap"); m_capStyle.setId("Cap");
m_joinStyle.setId("Join"); m_joinStyle.setId("Join");
m_miterJoinLimit.setId("Miter"); m_miterJoinLimit.setId("Miter");
m_snapGrid.setId("SnapGrid");
} }
//------------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------
@ -777,6 +782,7 @@ void ToonzVectorBrushTool::leftButtonDown(const TPointD &pos,
// updating m_brushPos is needed to refresh viewer properly // updating m_brushPos is needed to refresh viewer properly
m_brushPos = m_mousePos = pos; m_brushPos = m_mousePos = pos;
m_perspectiveIndex = -1;
} }
//------------------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------------
@ -792,42 +798,44 @@ void ToonzVectorBrushTool::leftButtonDrag(const TPointD &pos,
m_lastPoint = pos; m_lastPoint = pos;
bool nonShiftStraight = false; bool nonShiftStraight = false;
TPointD usePos = pos;
if (!m_isPath && if (!m_isPath &&
(e.isAltPressed() && !e.isCtrlPressed() && !e.isShiftPressed())) { ((e.isAltPressed() && !e.isCtrlPressed() && !e.isShiftPressed()) ||
m_snapGrid.getValue())) {
invalidateRect = TRectD(m_firstPoint, m_lastPoint).enlarge(2); invalidateRect = TRectD(m_firstPoint, m_lastPoint).enlarge(2);
nonShiftStraight = true; if (!m_snapGrid.getValue()) nonShiftStraight = true;
double distance = (m_brushPos.x) * 0.5; double distance = (m_brushPos.x) * 0.5;
TRectD brushRect = TRectD brushRect =
TRectD(TPointD(m_brushPos.x - distance, m_brushPos.y - distance), TRectD(TPointD(m_brushPos.x - distance, m_brushPos.y - distance),
TPointD(m_brushPos.x + distance, m_brushPos.y + distance)); TPointD(m_brushPos.x + distance, m_brushPos.y + distance));
invalidateRect += (brushRect); invalidateRect += (brushRect);
// let's get info about our current location
double denominator = m_lastPoint.x - m_firstPoint.x;
double numerator = m_lastPoint.y - m_firstPoint.y;
if (areAlmostEqual(denominator, 0.0, 0.0001)) {
denominator = denominator < 0 ? -0.0001 : 0.0001;
}
if (areAlmostEqual(numerator, 0.0, 0.0001)) {
numerator = numerator < 0 ? -0.0001 : 0.0001;
}
double slope = (numerator / denominator);
double angle = std::atan(slope) * (180 / 3.14159);
// now let's get the angle of each of the assistant points
std::vector<double> anglesToAssistants;
TPointD pointToUse = TPointD(0.0, 0.0);
PerspectiveTool *perspectiveTool = dynamic_cast<PerspectiveTool *>( PerspectiveTool *perspectiveTool = dynamic_cast<PerspectiveTool *>(
TTool::getTool("T_PerspectiveGrid", TTool::VectorImage)); TTool::getTool("T_PerspectiveGrid", TTool::VectorImage));
if (perspectiveTool) { std::vector<PerspectiveObject *> perspectiveObjs =
TPointD dpiScale = getViewer()->getDpiScale(); perspectiveTool->getPerspectiveObjects();
TPointD refPoint = m_firstPoint; TPointD pointToUse = TPointD(0.0, 0.0);
refPoint.x *= dpiScale.x; TPointD dpiScale = getViewer()->getDpiScale();
refPoint.y *= dpiScale.y; TPointD refPoint = m_firstPoint;
refPoint.x *= dpiScale.x;
refPoint.y *= dpiScale.y;
if ((e.isAltPressed() && !e.isCtrlPressed() && !e.isShiftPressed()) ||
m_perspectiveIndex < 0) {
// let's get info about our current location
double denominator = m_lastPoint.x - m_firstPoint.x;
double numerator = m_lastPoint.y - m_firstPoint.y;
if (areAlmostEqual(denominator, 0.0, 0.0001)) {
denominator = denominator < 0 ? -0.0001 : 0.0001;
}
if (areAlmostEqual(numerator, 0.0, 0.0001)) {
numerator = numerator < 0 ? -0.0001 : 0.0001;
}
double slope = (numerator / denominator);
double angle = std::atan(slope) * (180 / 3.14159);
std::vector<PerspectiveObject *> perspectiveObjs = // now let's get the angle of each of the assistant points
perspectiveTool->getPerspectiveObjects(); std::vector<double> anglesToAssistants;
for (auto data : perspectiveObjs) { for (auto data : perspectiveObjs) {
TPointD point = data->getReferencePoint(refPoint); TPointD point = data->getReferencePoint(refPoint);
point.x /= dpiScale.x; point.x /= dpiScale.x;
@ -856,8 +864,14 @@ void ToonzVectorBrushTool::leftButtonDrag(const TPointD &pos,
pointToUse = perspectiveObjs.at(i)->getReferencePoint(refPoint); pointToUse = perspectiveObjs.at(i)->getReferencePoint(refPoint);
pointToUse.x /= dpiScale.x; pointToUse.x /= dpiScale.x;
pointToUse.y /= dpiScale.y; pointToUse.y /= dpiScale.y;
m_perspectiveIndex = i;
} }
} }
} else {
pointToUse =
perspectiveObjs.at(m_perspectiveIndex)->getReferencePoint(refPoint);
pointToUse.x /= dpiScale.x;
pointToUse.y /= dpiScale.y;
} }
double distanceFirstToLast = double distanceFirstToLast =
@ -887,7 +901,7 @@ void ToonzVectorBrushTool::leftButtonDrag(const TPointD &pos,
newY = ((1 - ratio) * m_firstPoint.y) + (ratio * pointToUse.y); newY = ((1 - ratio) * m_firstPoint.y) + (ratio * pointToUse.y);
} }
m_lastPoint = TPointD(newX, newY); usePos = m_lastPoint = TPointD(newX, newY);
invalidateRect += TRectD(m_firstPoint, m_lastPoint).enlarge(2); invalidateRect += TRectD(m_firstPoint, m_lastPoint).enlarge(2);
} else if (e.isCtrlPressed() && !e.isAltPressed() && !e.isShiftPressed()) { } else if (e.isCtrlPressed() && !e.isAltPressed() && !e.isShiftPressed()) {
invalidateRect = TRectD(m_firstPoint, m_lastPoint).enlarge(2); invalidateRect = TRectD(m_firstPoint, m_lastPoint).enlarge(2);
@ -947,7 +961,7 @@ void ToonzVectorBrushTool::leftButtonDrag(const TPointD &pos,
} }
} }
m_lastDragPos = pos; m_lastDragPos = usePos;
m_lastDragEvent = e; m_lastDragEvent = e;
double thickness = (m_pressure.getValue() || m_isPath) double thickness = (m_pressure.getValue() || m_isPath)
@ -994,7 +1008,8 @@ void ToonzVectorBrushTool::leftButtonDrag(const TPointD &pos,
m_track.removeMiddlePoints(); m_track.removeMiddlePoints();
invalidateRect += m_track.getModifiedRegion(); invalidateRect += m_track.getModifiedRegion();
} else if (m_dragDraw) { } else if (m_dragDraw) {
addTrackPoint(TThickPoint(pos, thickness), getPixelSize() * getPixelSize()); addTrackPoint(TThickPoint(usePos, thickness),
getPixelSize() * getPixelSize());
invalidateRect += m_track.getLastModifiedRegion(); invalidateRect += m_track.getLastModifiedRegion();
} }
@ -1076,6 +1091,7 @@ void ToonzVectorBrushTool::leftButtonUp(const TPointD &pos,
notifyImageChanged(); notifyImageChanged();
TUndoManager::manager()->add(undo); TUndoManager::manager()->add(undo);
m_perspectiveIndex = -1;
return; return;
} }
@ -1083,7 +1099,7 @@ void ToonzVectorBrushTool::leftButtonUp(const TPointD &pos,
if (m_track.isEmpty()) { if (m_track.isEmpty()) {
m_styleId = 0; m_styleId = 0;
m_track.clear(); m_track.clear();
m_perspectiveIndex = -1;
return; return;
} }
@ -1237,6 +1253,7 @@ void ToonzVectorBrushTool::leftButtonUp(const TPointD &pos,
assert(stroke); assert(stroke);
m_track.clear(); m_track.clear();
m_toggleSnap = false; m_toggleSnap = false;
m_perspectiveIndex = -1;
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -1891,6 +1908,7 @@ bool ToonzVectorBrushTool::onPropertyChanged(std::string propertyName) {
V_VectorBrushSnap = m_snap.getValue(); V_VectorBrushSnap = m_snap.getValue();
int snapSensitivityIndex = m_snapSensitivity.getIndex(); int snapSensitivityIndex = m_snapSensitivity.getIndex();
V_VectorBrushSnapSensitivity = snapSensitivityIndex; V_VectorBrushSnapSensitivity = snapSensitivityIndex;
V_VectorBrushSnapGrid = m_snapGrid.getValue();
// Recalculate/reset based on changed settings // Recalculate/reset based on changed settings
m_minThick = m_thickness.getValue().first; m_minThick = m_thickness.getValue().first;
@ -2067,6 +2085,7 @@ void ToonzVectorBrushTool::loadLastBrush() {
m_autoGroup.setValue(V_VectorBrushAutoGroup); m_autoGroup.setValue(V_VectorBrushAutoGroup);
m_autoClose.setValue(V_VectorBrushAutoClose); m_autoClose.setValue(V_VectorBrushAutoClose);
m_autoFill.setValue(V_VectorBrushAutoFill); m_autoFill.setValue(V_VectorBrushAutoFill);
m_snapGrid.setValue(V_VectorBrushSnapGrid);
// Recalculate based on prior values // Recalculate based on prior values
m_minThick = m_thickness.getValue().first; m_minThick = m_thickness.getValue().first;

View file

@ -163,6 +163,7 @@ protected:
TEnumProperty m_capStyle; TEnumProperty m_capStyle;
TEnumProperty m_joinStyle; TEnumProperty m_joinStyle;
TIntProperty m_miterJoinLimit; TIntProperty m_miterJoinLimit;
TBoolProperty m_snapGrid;
StrokeGenerator m_track; StrokeGenerator m_track;
StrokeGenerator m_rangeTrack; StrokeGenerator m_rangeTrack;
@ -215,6 +216,8 @@ protected:
TPointD m_firstPoint; TPointD m_firstPoint;
TPointD m_lastPoint; TPointD m_lastPoint;
int m_perspectiveIndex = -1;
}; };
#endif // TOONZVECTORBRUSHTOOL_H #endif // TOONZVECTORBRUSHTOOL_H