2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "tstroke.h"
|
|
|
|
|
#include "tools/toolutils.h"
|
|
|
|
|
#include "tools/tool.h"
|
|
|
|
|
#include "tmathutil.h"
|
|
|
|
|
#include "tools/cursors.h"
|
|
|
|
|
#include "drawutil.h"
|
|
|
|
|
#include "tcolorstyles.h"
|
|
|
|
|
#include "tundo.h"
|
|
|
|
|
#include "tvectorimage.h"
|
|
|
|
|
#include "ttoonzimage.h"
|
|
|
|
|
#include "tproperty.h"
|
|
|
|
|
#include "toonz/ttilesaver.h"
|
|
|
|
|
#include "toonz/txshsimplelevel.h"
|
|
|
|
|
#include "toonz/observer.h"
|
|
|
|
|
#include "toonz/toonzimageutils.h"
|
|
|
|
|
#include "toonz/levelproperties.h"
|
|
|
|
|
#include "toonz/stage2.h"
|
|
|
|
|
#include "toonz/ttileset.h"
|
2018-05-17 18:03:05 +12:00
|
|
|
|
#include "toonz/preferences.h"
|
2016-03-19 06:57:51 +13:00
|
|
|
|
#include "tgl.h"
|
|
|
|
|
#include "tenv.h"
|
|
|
|
|
|
|
|
|
|
#include "trop.h"
|
|
|
|
|
|
|
|
|
|
#include "tinbetween.h"
|
|
|
|
|
#include "ttile.h"
|
|
|
|
|
|
|
|
|
|
#include "toonz/tpalettehandle.h"
|
|
|
|
|
#include "toonz/txsheethandle.h"
|
|
|
|
|
#include "toonz/txshlevelhandle.h"
|
|
|
|
|
#include "toonz/tframehandle.h"
|
|
|
|
|
#include "tools/toolhandle.h"
|
|
|
|
|
|
|
|
|
|
// For Qt translation support
|
|
|
|
|
#include <QCoreApplication>
|
|
|
|
|
|
2021-06-03 07:42:54 +12:00
|
|
|
|
#include "tools/stylepicker.h"
|
|
|
|
|
#include "toonzqt/styleselection.h"
|
|
|
|
|
|
2023-02-04 15:05:42 +13:00
|
|
|
|
#include "cmrasterbrush.h"
|
|
|
|
|
#include "symmetrytool.h"
|
|
|
|
|
|
2016-03-19 06:57:51 +13:00
|
|
|
|
using namespace ToolUtils;
|
|
|
|
|
|
|
|
|
|
#define LINES L"Lines"
|
|
|
|
|
#define AREAS L"Areas"
|
|
|
|
|
#define ALL L"Lines & Areas"
|
|
|
|
|
|
|
|
|
|
TEnv::StringVar PaintBrushColorType("InknpaintPaintBrushColorType", "Areas");
|
|
|
|
|
TEnv::IntVar PaintBrushSelective("InknpaintPaintBrushSelective", 0);
|
2021-06-02 13:36:13 +12:00
|
|
|
|
TEnv::DoubleVar PaintBrushSizeMax("InknpaintPaintBrushSizeMax", 10);
|
|
|
|
|
TEnv::DoubleVar PaintBrushSizeMin("InknpaintPaintBrushSizeMin", 10);
|
|
|
|
|
TEnv::IntVar PaintBrushPressureSensitivity("InknpaintBrushPressureSensitivity",
|
|
|
|
|
1);
|
2021-06-04 01:36:17 +12:00
|
|
|
|
TEnv::IntVar PaintBrushModifierLockAlpha("PaintBrushModifierLockAlpha", 0);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
const int BackgroundStyle = 0;
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
namespace {
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
2016-06-29 18:17:12 +12:00
|
|
|
|
class BrushUndo final : public TRasterUndo {
|
2016-06-15 18:43:10 +12:00
|
|
|
|
std::vector<TThickPoint> m_points;
|
|
|
|
|
int m_styleId;
|
|
|
|
|
bool m_selective;
|
|
|
|
|
ColorType m_colorType;
|
2021-06-04 01:36:17 +12:00
|
|
|
|
bool m_modifierLockAlpha;
|
2023-02-04 15:05:42 +13:00
|
|
|
|
TPointD m_dpiScale;
|
|
|
|
|
double m_brushCount;
|
|
|
|
|
double m_rotation;
|
|
|
|
|
TPointD m_centerPoint;
|
|
|
|
|
bool m_useLineSymmetry;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
|
BrushUndo(TTileSetCM32 *tileSet, const std::vector<TThickPoint> &points,
|
|
|
|
|
ColorType colorType, int styleId, bool selective,
|
2023-02-04 15:05:42 +13:00
|
|
|
|
TXshSimpleLevel *level, const TFrameId &frameId, bool lockAlpha,
|
|
|
|
|
TPointD dpiScale, double symmetryLines, double rotation,
|
|
|
|
|
TPointD centerPoint, bool useLineSymmetry)
|
2016-06-15 18:43:10 +12:00
|
|
|
|
: TRasterUndo(tileSet, level, frameId, false, false, 0)
|
|
|
|
|
, m_points(points)
|
|
|
|
|
, m_styleId(styleId)
|
|
|
|
|
, m_selective(selective)
|
2021-06-04 01:36:17 +12:00
|
|
|
|
, m_colorType(colorType)
|
2023-02-04 15:05:42 +13:00
|
|
|
|
, m_modifierLockAlpha(lockAlpha)
|
|
|
|
|
, m_dpiScale(dpiScale)
|
|
|
|
|
, m_brushCount(symmetryLines)
|
|
|
|
|
, m_rotation(rotation)
|
|
|
|
|
, m_centerPoint(centerPoint)
|
|
|
|
|
, m_useLineSymmetry(useLineSymmetry) {}
|
2016-06-15 18:43:10 +12:00
|
|
|
|
|
2016-06-19 20:06:29 +12:00
|
|
|
|
void redo() const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
|
TToonzImageP image = m_level->getFrame(m_frameId, true);
|
|
|
|
|
TRasterCM32P ras = image->getRaster();
|
2023-02-04 15:05:42 +13:00
|
|
|
|
CMRasterBrush m_cmRasterBrush(ras, PAINTBRUSH, m_colorType, m_styleId,
|
|
|
|
|
m_points[0], m_selective, 0,
|
|
|
|
|
m_modifierLockAlpha, false);
|
|
|
|
|
if (m_brushCount > 1)
|
|
|
|
|
m_cmRasterBrush.addSymmetryBrushes(m_brushCount, m_rotation,
|
|
|
|
|
m_centerPoint, m_useLineSymmetry,
|
|
|
|
|
m_dpiScale);
|
|
|
|
|
|
|
|
|
|
m_cmRasterBrush.setPointsSequence(m_points);
|
|
|
|
|
m_cmRasterBrush.generateStroke(true);
|
|
|
|
|
image->setSavebox(
|
|
|
|
|
image->getSavebox() +
|
|
|
|
|
m_cmRasterBrush.getBBox(m_cmRasterBrush.getPointsSequence()));
|
2016-06-15 18:43:10 +12:00
|
|
|
|
ToolUtils::updateSaveBox();
|
|
|
|
|
TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged();
|
|
|
|
|
notifyImageChanged();
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-20 14:23:05 +12:00
|
|
|
|
int getSize() const override {
|
|
|
|
|
return sizeof(*this) + TRasterUndo::getSize();
|
|
|
|
|
}
|
2016-06-19 20:06:29 +12:00
|
|
|
|
|
|
|
|
|
QString getToolName() override { return QString("Paint Brush Tool"); }
|
|
|
|
|
int getHistoryType() override { return HistoryType::PaintBrushTool; }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------------------
|
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
void drawLine(const TPointD &point, const TPointD ¢re, bool horizontal,
|
|
|
|
|
bool isDecimal) {
|
|
|
|
|
if (!isDecimal) {
|
|
|
|
|
if (horizontal) {
|
|
|
|
|
tglDrawSegment(TPointD(point.x - 1.5, point.y + 0.5) + centre,
|
|
|
|
|
TPointD(point.x - 0.5, point.y + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(point.y - 0.5, -point.x + 1.5) + centre,
|
|
|
|
|
TPointD(point.y - 0.5, -point.x + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.x + 0.5, -point.y + 0.5) + centre,
|
|
|
|
|
TPointD(-point.x - 0.5, -point.y + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.y - 0.5, point.x - 0.5) + centre,
|
|
|
|
|
TPointD(-point.y - 0.5, point.x + 0.5) + centre);
|
|
|
|
|
|
|
|
|
|
tglDrawSegment(TPointD(point.y - 0.5, point.x + 0.5) + centre,
|
|
|
|
|
TPointD(point.y - 0.5, point.x - 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(point.x - 0.5, -point.y + 0.5) + centre,
|
|
|
|
|
TPointD(point.x - 1.5, -point.y + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.y - 0.5, -point.x + 0.5) + centre,
|
|
|
|
|
TPointD(-point.y - 0.5, -point.x + 1.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.x - 0.5, point.y + 0.5) + centre,
|
|
|
|
|
TPointD(-point.x + 0.5, point.y + 0.5) + centre);
|
|
|
|
|
} else {
|
|
|
|
|
tglDrawSegment(TPointD(point.x - 1.5, point.y + 1.5) + centre,
|
|
|
|
|
TPointD(point.x - 1.5, point.y + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(point.x - 1.5, point.y + 0.5) + centre,
|
|
|
|
|
TPointD(point.x - 0.5, point.y + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(point.y + 0.5, -point.x + 1.5) + centre,
|
|
|
|
|
TPointD(point.y - 0.5, -point.x + 1.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(point.y - 0.5, -point.x + 1.5) + centre,
|
|
|
|
|
TPointD(point.y - 0.5, -point.x + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.x + 0.5, -point.y - 0.5) + centre,
|
|
|
|
|
TPointD(-point.x + 0.5, -point.y + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.x + 0.5, -point.y + 0.5) + centre,
|
|
|
|
|
TPointD(-point.x - 0.5, -point.y + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.y - 1.5, point.x - 0.5) + centre,
|
|
|
|
|
TPointD(-point.y - 0.5, point.x - 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.y - 0.5, point.x - 0.5) + centre,
|
|
|
|
|
TPointD(-point.y - 0.5, point.x + 0.5) + centre);
|
|
|
|
|
|
|
|
|
|
tglDrawSegment(TPointD(point.y + 0.5, point.x - 0.5) + centre,
|
|
|
|
|
TPointD(point.y - 0.5, point.x - 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(point.y - 0.5, point.x - 0.5) + centre,
|
|
|
|
|
TPointD(point.y - 0.5, point.x + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(point.x - 1.5, -point.y - 0.5) + centre,
|
|
|
|
|
TPointD(point.x - 1.5, -point.y + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(point.x - 1.5, -point.y + 0.5) + centre,
|
|
|
|
|
TPointD(point.x - 0.5, -point.y + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.y - 1.5, -point.x + 1.5) + centre,
|
|
|
|
|
TPointD(-point.y - 0.5, -point.x + 1.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.y - 0.5, -point.x + 1.5) + centre,
|
|
|
|
|
TPointD(-point.y - 0.5, -point.x + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.x + 0.5, point.y + 1.5) + centre,
|
|
|
|
|
TPointD(-point.x + 0.5, point.y + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.x + 0.5, point.y + 0.5) + centre,
|
|
|
|
|
TPointD(-point.x - 0.5, point.y + 0.5) + centre);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (horizontal) {
|
|
|
|
|
tglDrawSegment(TPointD(point.x - 0.5, point.y + 0.5) + centre,
|
|
|
|
|
TPointD(point.x + 0.5, point.y + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(point.y + 0.5, point.x - 0.5) + centre,
|
|
|
|
|
TPointD(point.y + 0.5, point.x + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(point.y + 0.5, -point.x + 0.5) + centre,
|
|
|
|
|
TPointD(point.y + 0.5, -point.x - 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(point.x + 0.5, -point.y - 0.5) + centre,
|
|
|
|
|
TPointD(point.x - 0.5, -point.y - 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.x - 0.5, -point.y - 0.5) + centre,
|
|
|
|
|
TPointD(-point.x + 0.5, -point.y - 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.y - 0.5, -point.x + 0.5) + centre,
|
|
|
|
|
TPointD(-point.y - 0.5, -point.x - 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.y - 0.5, point.x - 0.5) + centre,
|
|
|
|
|
TPointD(-point.y - 0.5, point.x + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.x + 0.5, point.y + 0.5) + centre,
|
|
|
|
|
TPointD(-point.x - 0.5, point.y + 0.5) + centre);
|
|
|
|
|
} else {
|
|
|
|
|
tglDrawSegment(TPointD(point.x - 0.5, point.y + 1.5) + centre,
|
|
|
|
|
TPointD(point.x - 0.5, point.y + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(point.x - 0.5, point.y + 0.5) + centre,
|
|
|
|
|
TPointD(point.x + 0.5, point.y + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(point.y + 1.5, point.x - 0.5) + centre,
|
|
|
|
|
TPointD(point.y + 0.5, point.x - 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(point.y + 0.5, point.x - 0.5) + centre,
|
|
|
|
|
TPointD(point.y + 0.5, point.x + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(point.y + 1.5, -point.x + 0.5) + centre,
|
|
|
|
|
TPointD(point.y + 0.5, -point.x + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(point.y + 0.5, -point.x + 0.5) + centre,
|
|
|
|
|
TPointD(point.y + 0.5, -point.x - 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(point.x - 0.5, -point.y - 1.5) + centre,
|
|
|
|
|
TPointD(point.x - 0.5, -point.y - 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(point.x - 0.5, -point.y - 0.5) + centre,
|
|
|
|
|
TPointD(point.x + 0.5, -point.y - 0.5) + centre);
|
|
|
|
|
|
|
|
|
|
tglDrawSegment(TPointD(-point.x + 0.5, -point.y - 1.5) + centre,
|
|
|
|
|
TPointD(-point.x + 0.5, -point.y - 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.x + 0.5, -point.y - 0.5) + centre,
|
|
|
|
|
TPointD(-point.x - 0.5, -point.y - 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.y - 1.5, -point.x + 0.5) + centre,
|
|
|
|
|
TPointD(-point.y - 0.5, -point.x + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.y - 0.5, -point.x + 0.5) + centre,
|
|
|
|
|
TPointD(-point.y - 0.5, -point.x - 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.y - 1.5, point.x - 0.5) + centre,
|
|
|
|
|
TPointD(-point.y - 0.5, point.x - 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.y - 0.5, point.x - 0.5) + centre,
|
|
|
|
|
TPointD(-point.y - 0.5, point.x + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.x + 0.5, point.y + 1.5) + centre,
|
|
|
|
|
TPointD(-point.x + 0.5, point.y + 0.5) + centre);
|
|
|
|
|
tglDrawSegment(TPointD(-point.x + 0.5, point.y + 0.5) + centre,
|
|
|
|
|
TPointD(-point.x - 0.5, point.y + 0.5) + centre);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
void drawEmptyCircle(int thick, const TPointD &mousePos, bool isPencil,
|
|
|
|
|
bool isLxEven, bool isLyEven) {
|
|
|
|
|
TPointD pos = mousePos;
|
|
|
|
|
if (isLxEven) pos.x += 0.5;
|
|
|
|
|
if (isLyEven) pos.y += 0.5;
|
|
|
|
|
if (!isPencil)
|
|
|
|
|
tglDrawCircle(pos, (thick + 1) * 0.5);
|
|
|
|
|
else {
|
|
|
|
|
int x = 0, y = tround((thick * 0.5) - 0.5);
|
|
|
|
|
int d = 3 - 2 * (int)(thick * 0.5);
|
|
|
|
|
bool horizontal = true, isDecimal = thick % 2 != 0;
|
|
|
|
|
drawLine(TPointD(x, y), pos, horizontal, isDecimal);
|
|
|
|
|
while (y > x) {
|
|
|
|
|
if (d < 0) {
|
|
|
|
|
d = d + 4 * x + 6;
|
|
|
|
|
horizontal = true;
|
|
|
|
|
} else {
|
|
|
|
|
d = d + 4 * (x - y) + 10;
|
|
|
|
|
horizontal = false;
|
|
|
|
|
y--;
|
|
|
|
|
}
|
|
|
|
|
x++;
|
|
|
|
|
drawLine(TPointD(x, y), pos, horizontal, isDecimal);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-02 13:36:13 +12:00
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
double computeThickness(double pressure, const TDoublePairProperty &property) {
|
|
|
|
|
double t = pressure * pressure * pressure;
|
|
|
|
|
double thick0 = property.getValue().first;
|
|
|
|
|
double thick1 = property.getValue().second;
|
|
|
|
|
if (thick1 < 0.0001) thick0 = thick1 = 0.0;
|
|
|
|
|
return (thick0 + (thick1 - thick0) * t) * 0.5;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
} // namespace
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2016-06-29 18:17:12 +12:00
|
|
|
|
class PaintBrushTool final : public TTool {
|
2016-06-15 18:43:10 +12:00
|
|
|
|
Q_DECLARE_TR_FUNCTIONS(PaintBrushTool)
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
2023-02-04 15:05:42 +13:00
|
|
|
|
CMRasterBrush *m_cmRasterBrush;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
bool m_firstTime;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
bool m_selecting;
|
|
|
|
|
TTileSaverCM32 *m_tileSaver;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
TPointD m_mousePos;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
2021-06-02 13:36:13 +12:00
|
|
|
|
TDoublePairProperty m_rasThickness;
|
|
|
|
|
TBoolProperty m_pressure;
|
2016-06-15 18:43:10 +12:00
|
|
|
|
TBoolProperty m_onlyEmptyAreas;
|
|
|
|
|
TEnumProperty m_colorType;
|
|
|
|
|
TPropertyGroup m_prop;
|
|
|
|
|
int m_cursor;
|
|
|
|
|
ColorType m_colorTypeBrush;
|
|
|
|
|
/*--
|
|
|
|
|
描画開始時のFrameIdを保存し、マウスリリース時(Undoの登録時)に別のフレームに
|
|
|
|
|
移動している場合に備える --*/
|
|
|
|
|
TFrameId m_workingFrameId;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
2021-06-02 13:36:13 +12:00
|
|
|
|
double m_minThick, m_maxThick;
|
|
|
|
|
|
2021-06-03 07:42:54 +12:00
|
|
|
|
Tasks m_task;
|
|
|
|
|
|
2021-06-04 01:36:17 +12:00
|
|
|
|
TBoolProperty m_modifierLockAlpha;
|
|
|
|
|
|
2021-06-03 07:42:54 +12:00
|
|
|
|
int getStyleUnderCursor(const TPointD &pos);
|
|
|
|
|
|
2016-03-19 06:57:51 +13:00
|
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
|
PaintBrushTool();
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
2016-06-19 20:06:29 +12:00
|
|
|
|
ToolType getToolType() const override { return TTool::LevelWriteTool; }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
2016-06-19 20:06:29 +12:00
|
|
|
|
void draw() override;
|
2016-06-15 18:43:10 +12:00
|
|
|
|
void update(TToonzImageP ti, TRectD area);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
2016-06-19 20:06:29 +12:00
|
|
|
|
void updateTranslation() override;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
2016-06-19 20:06:29 +12:00
|
|
|
|
void leftButtonDown(const TPointD &pos, const TMouseEvent &e) override;
|
|
|
|
|
void leftButtonDrag(const TPointD &pos, const TMouseEvent &e) override;
|
|
|
|
|
void leftButtonUp(const TPointD &pos, const TMouseEvent &) override;
|
|
|
|
|
void mouseMove(const TPointD &pos, const TMouseEvent &e) override;
|
|
|
|
|
void onEnter() override;
|
|
|
|
|
void onLeave() override;
|
|
|
|
|
void onActivate() override;
|
|
|
|
|
void onDeactivate() override;
|
|
|
|
|
bool onPropertyChanged(std::string propertyName) override;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
2016-06-19 20:06:29 +12:00
|
|
|
|
TPropertyGroup *getProperties(int targetType) override { return &m_prop; }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
2016-06-19 20:06:29 +12:00
|
|
|
|
int getCursorId() const override { return m_cursor; }
|
2020-05-12 17:16:59 +12:00
|
|
|
|
TPointD getCenteredCursorPos(const TPointD &originalCursorPos);
|
|
|
|
|
void fixMousePos(TPointD pos, bool precise = false);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
int getColorClass() const { return 2; }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
/*---
|
|
|
|
|
* 描画中にツールが切り替わった場合に備え、onDeactivateにもMouseReleaseと同じ終了処理を行う
|
|
|
|
|
* ---*/
|
2021-06-02 13:36:13 +12:00
|
|
|
|
void finishBrush(double pressureValue);
|
2016-06-15 18:43:10 +12:00
|
|
|
|
/*--- Brush、PaintBrush、EraserToolがPencilModeのときにTrueを返す。
|
|
|
|
|
PaintBrushはピクセルのStyleIndexを入れ替えるツールのため、
|
|
|
|
|
アンチエイリアスは存在しない、いわば常にPencilMode ---*/
|
2016-06-19 20:06:29 +12:00
|
|
|
|
bool isPencilModeActive() override { return true; }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
PaintBrushTool paintBrushTool;
|
|
|
|
|
|
|
|
|
|
//=============================================================================
|
|
|
|
|
//
|
2021-07-08 13:39:28 +12:00
|
|
|
|
// InkPaintTool implementation
|
2016-03-19 06:57:51 +13:00
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
PaintBrushTool::PaintBrushTool()
|
2016-06-15 18:43:10 +12:00
|
|
|
|
: TTool("T_PaintBrush")
|
2023-02-04 15:05:42 +13:00
|
|
|
|
, m_cmRasterBrush(0)
|
2016-06-15 18:43:10 +12:00
|
|
|
|
, m_selecting(false)
|
|
|
|
|
, m_tileSaver(0)
|
|
|
|
|
, m_cursor(ToolCursor::EraserCursor)
|
|
|
|
|
// sostituire i nomi con quelli del current, tipo W_ToolOptions...
|
2021-06-02 13:36:13 +12:00
|
|
|
|
, m_rasThickness("Size:", 1, 1000, 10, 5)
|
2019-10-11 16:13:41 +13:00
|
|
|
|
, m_colorType("Mode:") // W_ToolOptions_InkOrPaint
|
|
|
|
|
, m_onlyEmptyAreas("Selective", false) // W_ToolOptions_Selective
|
2016-06-15 18:43:10 +12:00
|
|
|
|
, m_firstTime(true)
|
2021-06-02 13:36:13 +12:00
|
|
|
|
, m_pressure("Pressure", true)
|
2021-06-03 07:42:54 +12:00
|
|
|
|
, m_task(PAINTBRUSH)
|
2021-06-04 01:36:17 +12:00
|
|
|
|
, m_workingFrameId(TFrameId())
|
|
|
|
|
, m_modifierLockAlpha("Lock Alpha", false) {
|
2021-06-02 13:36:13 +12:00
|
|
|
|
m_rasThickness.setNonLinearSlider();
|
2019-10-11 16:13:41 +13:00
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
m_colorType.addValue(LINES);
|
|
|
|
|
m_colorType.addValue(AREAS);
|
|
|
|
|
m_colorType.addValue(ALL);
|
|
|
|
|
|
|
|
|
|
bind(TTool::ToonzImage);
|
|
|
|
|
|
2021-06-02 13:36:13 +12:00
|
|
|
|
m_prop.bind(m_rasThickness);
|
2016-06-15 18:43:10 +12:00
|
|
|
|
m_prop.bind(m_colorType);
|
|
|
|
|
m_prop.bind(m_onlyEmptyAreas);
|
2021-06-02 13:36:13 +12:00
|
|
|
|
m_prop.bind(m_pressure);
|
2021-06-04 01:36:17 +12:00
|
|
|
|
m_prop.bind(m_modifierLockAlpha);
|
2016-06-15 18:43:10 +12:00
|
|
|
|
|
|
|
|
|
m_onlyEmptyAreas.setId("Selective");
|
|
|
|
|
m_colorType.setId("Mode");
|
2021-06-02 13:36:13 +12:00
|
|
|
|
m_pressure.setId("PressureSensitivity");
|
2021-06-04 01:36:17 +12:00
|
|
|
|
m_modifierLockAlpha.setId("LockAlpha");
|
2016-03-19 06:57:51 +13:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
void PaintBrushTool::updateTranslation() {
|
2021-06-02 13:36:13 +12:00
|
|
|
|
m_rasThickness.setQStringName(tr("Size:"));
|
2018-04-26 21:24:25 +12:00
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
m_colorType.setQStringName(tr("Mode:"));
|
2018-04-26 21:24:25 +12:00
|
|
|
|
m_colorType.setItemUIName(LINES, tr("Lines"));
|
|
|
|
|
m_colorType.setItemUIName(AREAS, tr("Areas"));
|
|
|
|
|
m_colorType.setItemUIName(ALL, tr("Lines & Areas"));
|
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
m_onlyEmptyAreas.setQStringName(tr("Selective", NULL));
|
2021-06-02 13:36:13 +12:00
|
|
|
|
|
|
|
|
|
m_pressure.setQStringName(tr("Pressure"));
|
2021-06-10 00:35:12 +12:00
|
|
|
|
|
2021-06-04 01:36:17 +12:00
|
|
|
|
m_modifierLockAlpha.setQStringName(tr("Lock Alpha"));
|
2016-03-19 06:57:51 +13:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-12 17:16:59 +12:00
|
|
|
|
//-------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
TPointD PaintBrushTool::getCenteredCursorPos(const TPointD &originalCursorPos) {
|
|
|
|
|
TXshLevelHandle *levelHandle = m_application->getCurrentLevel();
|
|
|
|
|
TXshSimpleLevel *level = levelHandle ? levelHandle->getSimpleLevel() : 0;
|
|
|
|
|
TDimension resolution =
|
|
|
|
|
level ? level->getProperties()->getImageRes() : TDimension(0, 0);
|
|
|
|
|
|
|
|
|
|
bool xEven = (resolution.lx % 2 == 0);
|
|
|
|
|
bool yEven = (resolution.ly % 2 == 0);
|
|
|
|
|
|
|
|
|
|
TPointD centeredCursorPos = originalCursorPos;
|
|
|
|
|
|
|
|
|
|
if (xEven) centeredCursorPos.x -= 0.5;
|
|
|
|
|
if (yEven) centeredCursorPos.y -= 0.5;
|
|
|
|
|
|
|
|
|
|
return centeredCursorPos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void PaintBrushTool::fixMousePos(TPointD pos, bool precise) {
|
|
|
|
|
m_mousePos = getCenteredCursorPos(pos);
|
|
|
|
|
if (precise) {
|
|
|
|
|
TPointD pp(tround(m_mousePos.x), tround(m_mousePos.y));
|
|
|
|
|
m_mousePos = pp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-19 06:57:51 +13:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
void PaintBrushTool::draw() {
|
2018-05-17 18:03:05 +12:00
|
|
|
|
// If toggled off, don't draw brush outline
|
|
|
|
|
if (!Preferences::instance()->isCursorOutlineEnabled()) return;
|
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
TToonzImageP ti = (TToonzImageP)getImage(false);
|
|
|
|
|
if (!ti) return;
|
|
|
|
|
TRasterP ras = ti->getRaster();
|
|
|
|
|
int lx = ras->getLx();
|
|
|
|
|
int ly = ras->getLy();
|
|
|
|
|
|
|
|
|
|
if ((ToonzCheck::instance()->getChecks() & ToonzCheck::eInk) ||
|
|
|
|
|
(ToonzCheck::instance()->getChecks() & ToonzCheck::ePaint) ||
|
|
|
|
|
(ToonzCheck::instance()->getChecks() & ToonzCheck::eInk1))
|
|
|
|
|
glColor3d(0.5, 0.8, 0.8);
|
|
|
|
|
else
|
|
|
|
|
glColor3d(1.0, 0.0, 0.0);
|
|
|
|
|
|
2021-06-02 13:36:13 +12:00
|
|
|
|
drawEmptyCircle(tround(m_rasThickness.getValue().second), m_mousePos, true,
|
|
|
|
|
lx % 2 == 0, ly % 2 == 0);
|
|
|
|
|
drawEmptyCircle(tround(m_rasThickness.getValue().first), m_mousePos, true,
|
|
|
|
|
lx % 2 == 0, ly % 2 == 0);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
const UINT pointCount = 20;
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
bool PaintBrushTool::onPropertyChanged(std::string propertyName) {
|
2021-06-02 13:36:13 +12:00
|
|
|
|
PaintBrushColorType = ::to_string(m_colorType.getValue());
|
|
|
|
|
PaintBrushSelective = (int)(m_onlyEmptyAreas.getValue());
|
|
|
|
|
PaintBrushSizeMin = m_rasThickness.getValue().first;
|
|
|
|
|
PaintBrushSizeMax = m_rasThickness.getValue().second;
|
|
|
|
|
PaintBrushPressureSensitivity = m_pressure.getValue();
|
2021-06-10 00:35:12 +12:00
|
|
|
|
PaintBrushModifierLockAlpha = (int)(m_modifierLockAlpha.getValue());
|
2016-06-15 18:43:10 +12:00
|
|
|
|
|
2021-06-02 13:36:13 +12:00
|
|
|
|
/*-- Size ---*/
|
|
|
|
|
if (propertyName == m_rasThickness.getName()) {
|
|
|
|
|
m_minThick = m_rasThickness.getValue().first;
|
|
|
|
|
m_maxThick = m_rasThickness.getValue().second;
|
2016-06-15 18:43:10 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Selective
|
|
|
|
|
else if (propertyName == m_onlyEmptyAreas.getName()) {
|
2021-06-04 01:36:17 +12:00
|
|
|
|
if (m_onlyEmptyAreas.getValue() && m_modifierLockAlpha.getValue())
|
|
|
|
|
m_modifierLockAlpha.setValue(false);
|
2016-06-15 18:43:10 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Areas, Lines etc.
|
|
|
|
|
else if (propertyName == m_colorType.getName()) {
|
|
|
|
|
/*--- ColorModelのCursor更新のためにSIGNALを出す ---*/
|
|
|
|
|
TTool::getApplication()->getCurrentTool()->notifyToolChanged();
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-04 01:36:17 +12:00
|
|
|
|
// Lock Alpha
|
|
|
|
|
else if (propertyName == m_modifierLockAlpha.getName()) {
|
|
|
|
|
if (m_modifierLockAlpha.getValue() && m_onlyEmptyAreas.getValue())
|
|
|
|
|
m_onlyEmptyAreas.setValue(false);
|
|
|
|
|
}
|
2016-06-15 18:43:10 +12:00
|
|
|
|
return true;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
void PaintBrushTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) {
|
2020-05-12 17:16:59 +12:00
|
|
|
|
fixMousePos(pos);
|
2021-06-03 07:42:54 +12:00
|
|
|
|
m_task = PAINTBRUSH;
|
2016-06-15 18:43:10 +12:00
|
|
|
|
m_selecting = true;
|
|
|
|
|
TImageP image(getImage(true));
|
|
|
|
|
if (m_colorType.getValue() == LINES) m_colorTypeBrush = INK;
|
|
|
|
|
if (m_colorType.getValue() == AREAS) m_colorTypeBrush = PAINT;
|
2020-05-12 17:16:59 +12:00
|
|
|
|
if (m_colorType.getValue() == ALL) m_colorTypeBrush = INKNPAINT;
|
2016-06-15 18:43:10 +12:00
|
|
|
|
|
|
|
|
|
if (TToonzImageP ti = image) {
|
|
|
|
|
TRasterCM32P ras = ti->getRaster();
|
|
|
|
|
if (ras) {
|
2021-06-02 13:36:13 +12:00
|
|
|
|
double maxThick = m_rasThickness.getValue().second;
|
|
|
|
|
double thickness =
|
|
|
|
|
(m_pressure.getValue())
|
|
|
|
|
? computeThickness(e.m_pressure, m_rasThickness) * 2
|
|
|
|
|
: maxThick;
|
|
|
|
|
|
|
|
|
|
if (m_pressure.getValue() && e.m_pressure == 1.0)
|
|
|
|
|
thickness = m_rasThickness.getValue().first;
|
|
|
|
|
|
2021-06-03 07:42:54 +12:00
|
|
|
|
int styleId = TTool::getApplication()->getCurrentLevelStyleIndex();
|
|
|
|
|
|
|
|
|
|
if (e.isCtrlPressed()) {
|
|
|
|
|
int styleIdUnderCursor = getStyleUnderCursor(m_mousePos);
|
|
|
|
|
if (styleIdUnderCursor > 0) styleId = styleIdUnderCursor;
|
|
|
|
|
m_task = FINGER;
|
2021-06-03 08:23:14 +12:00
|
|
|
|
} else if (e.isShiftPressed()) {
|
|
|
|
|
int styleIdUnderCursor = getStyleUnderCursor(m_mousePos);
|
|
|
|
|
if (styleIdUnderCursor > 0) {
|
|
|
|
|
styleId = styleIdUnderCursor;
|
|
|
|
|
getApplication()->setCurrentLevelStyleIndex(styleId);
|
|
|
|
|
}
|
2021-06-12 00:21:59 +12:00
|
|
|
|
m_selecting = false;
|
|
|
|
|
return;
|
2021-06-03 07:42:54 +12:00
|
|
|
|
}
|
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
TTileSetCM32 *tileSet = new TTileSetCM32(ras->getSize());
|
|
|
|
|
m_tileSaver = new TTileSaverCM32(ras, tileSet);
|
2023-02-04 15:05:42 +13:00
|
|
|
|
m_cmRasterBrush = new CMRasterBrush(
|
2021-06-03 07:42:54 +12:00
|
|
|
|
ras, m_task, m_colorTypeBrush, styleId,
|
2020-05-12 17:16:59 +12:00
|
|
|
|
TThickPoint(m_mousePos + convert(ras->getCenter()), thickness),
|
2021-06-04 01:36:17 +12:00
|
|
|
|
m_onlyEmptyAreas.getValue(), 0, m_modifierLockAlpha.getValue(),
|
|
|
|
|
false);
|
2023-02-04 15:05:42 +13:00
|
|
|
|
|
|
|
|
|
SymmetryTool *symmetryTool = dynamic_cast<SymmetryTool *>(
|
|
|
|
|
TTool::getTool("T_Symmetry", TTool::RasterImage));
|
|
|
|
|
if (symmetryTool && symmetryTool->isGuideEnabled()) {
|
|
|
|
|
TPointD dpiScale = getViewer()->getDpiScale();
|
|
|
|
|
SymmetryObject symmObj = symmetryTool->getSymmetryObject();
|
|
|
|
|
m_cmRasterBrush->addSymmetryBrushes(
|
|
|
|
|
symmObj.getLines(), symmObj.getRotation(), symmObj.getCenterPoint(),
|
|
|
|
|
symmObj.isUsingLineSymmetry(), dpiScale);
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
/*-- 現在のFidを記憶 --*/
|
|
|
|
|
m_workingFrameId = getFrameId();
|
2023-02-04 15:05:42 +13:00
|
|
|
|
m_tileSaver->save(m_cmRasterBrush->getLastRect());
|
|
|
|
|
m_cmRasterBrush->generateLastPieceOfStroke(true);
|
2016-06-15 18:43:10 +12:00
|
|
|
|
invalidate();
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
void PaintBrushTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &e) {
|
|
|
|
|
if (!m_selecting) return;
|
|
|
|
|
|
2020-05-12 17:16:59 +12:00
|
|
|
|
fixMousePos(pos);
|
2016-06-15 18:43:10 +12:00
|
|
|
|
if (TToonzImageP ri = TImageP(getImage(true))) {
|
|
|
|
|
/*--- マウスを動かしながらショートカットでこのツールに切り替わった場合、
|
2023-02-04 15:05:42 +13:00
|
|
|
|
いきなりleftButtonDragから呼ばれることがあり、m_cmRasterBrushが無い可能性がある
|
2016-06-15 18:43:10 +12:00
|
|
|
|
---*/
|
2023-02-04 15:05:42 +13:00
|
|
|
|
if (m_cmRasterBrush) {
|
2021-06-02 13:36:13 +12:00
|
|
|
|
double maxThick = m_rasThickness.getValue().second;
|
|
|
|
|
double thickness =
|
|
|
|
|
(m_pressure.getValue())
|
|
|
|
|
? computeThickness(e.m_pressure, m_rasThickness) * 2
|
|
|
|
|
: maxThick;
|
|
|
|
|
|
2021-06-03 07:42:54 +12:00
|
|
|
|
// If we were using FINGER mode before, but stopped mid drag, end previous
|
|
|
|
|
// stroke and switch
|
|
|
|
|
if (m_task == FINGER && !e.isCtrlPressed()) {
|
2021-06-12 00:17:54 +12:00
|
|
|
|
double pressure = m_pressure.getValue() && e.isTablet() ? e.m_pressure : 0.5;
|
|
|
|
|
finishBrush(pressure);
|
2021-06-03 07:42:54 +12:00
|
|
|
|
leftButtonDown(pos, e);
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-04 15:05:42 +13:00
|
|
|
|
m_cmRasterBrush->add(TThickPoint(
|
2020-05-12 17:16:59 +12:00
|
|
|
|
m_mousePos + convert(ri->getRaster()->getCenter()), thickness));
|
2023-02-04 15:05:42 +13:00
|
|
|
|
m_tileSaver->save(m_cmRasterBrush->getLastRect());
|
|
|
|
|
TRect modifiedBbox = m_cmRasterBrush->generateLastPieceOfStroke(true);
|
2018-06-18 16:01:39 +12:00
|
|
|
|
invalidate();
|
2016-06-15 18:43:10 +12:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2021-06-02 13:36:13 +12:00
|
|
|
|
void PaintBrushTool::leftButtonUp(const TPointD &pos, const TMouseEvent &e) {
|
2016-06-15 18:43:10 +12:00
|
|
|
|
if (!m_selecting) return;
|
2021-06-03 07:42:54 +12:00
|
|
|
|
m_task = PAINTBRUSH;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
2020-05-12 17:16:59 +12:00
|
|
|
|
fixMousePos(pos);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
2021-06-02 13:36:13 +12:00
|
|
|
|
double pressure = m_pressure.getValue() && e.isTablet() ? e.m_pressure : 0.5;
|
|
|
|
|
|
|
|
|
|
finishBrush(pressure);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
void PaintBrushTool::mouseMove(const TPointD &pos, const TMouseEvent &e) {
|
2020-05-12 17:16:59 +12:00
|
|
|
|
fixMousePos(pos, true);
|
2016-06-15 18:43:10 +12:00
|
|
|
|
invalidate();
|
2016-03-19 06:57:51 +13:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
void PaintBrushTool::onEnter() {
|
|
|
|
|
if (m_firstTime) {
|
|
|
|
|
m_onlyEmptyAreas.setValue(PaintBrushSelective ? 1 : 0);
|
|
|
|
|
m_colorType.setValue(::to_wstring(PaintBrushColorType.getValue()));
|
2021-06-02 13:36:13 +12:00
|
|
|
|
m_rasThickness.setValue(
|
|
|
|
|
TDoublePairProperty::Value(PaintBrushSizeMin, PaintBrushSizeMax));
|
|
|
|
|
m_pressure.setValue(PaintBrushPressureSensitivity ? 1 : 0);
|
2021-06-04 01:36:17 +12:00
|
|
|
|
m_modifierLockAlpha.setValue(PaintBrushModifierLockAlpha ? 1 : 0);
|
2016-06-15 18:43:10 +12:00
|
|
|
|
m_firstTime = false;
|
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
2021-06-02 13:36:13 +12:00
|
|
|
|
m_minThick = m_rasThickness.getValue().first;
|
|
|
|
|
m_maxThick = m_rasThickness.getValue().second;
|
2021-06-03 07:42:54 +12:00
|
|
|
|
m_task = PAINTBRUSH;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
if ((TToonzImageP)getImage(false))
|
|
|
|
|
m_cursor = ToolCursor::PenCursor;
|
|
|
|
|
else
|
|
|
|
|
m_cursor = ToolCursor::CURSOR_NO;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2021-06-02 13:36:13 +12:00
|
|
|
|
void PaintBrushTool::onLeave() {
|
|
|
|
|
m_minThick = 0;
|
|
|
|
|
m_maxThick = 0;
|
2021-06-03 07:42:54 +12:00
|
|
|
|
m_task = PAINTBRUSH;
|
2021-06-02 13:36:13 +12:00
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
void PaintBrushTool::onActivate() { onEnter(); }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
void PaintBrushTool::onDeactivate() {
|
|
|
|
|
/*--マウスドラッグ中(m_selecting=true)にツールが切り替わったときに描画の終了処理を行う---*/
|
2021-06-12 00:17:54 +12:00
|
|
|
|
if (m_selecting) finishBrush(1.0);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2016-06-15 18:43:10 +12:00
|
|
|
|
/*!
|
|
|
|
|
* 描画中にツールが切り替わった場合に備え、onDeactivateでもMouseReleaseと同じ終了処理を行う
|
2019-07-30 17:29:41 +12:00
|
|
|
|
*/
|
2021-06-02 13:36:13 +12:00
|
|
|
|
void PaintBrushTool::finishBrush(double pressureValue) {
|
2016-06-15 18:43:10 +12:00
|
|
|
|
if (TToonzImageP ti = (TToonzImageP)getImage(true)) {
|
2023-02-04 15:05:42 +13:00
|
|
|
|
if (m_cmRasterBrush) {
|
2021-06-02 13:36:13 +12:00
|
|
|
|
double maxThick = m_rasThickness.getValue().second;
|
|
|
|
|
double thickness =
|
|
|
|
|
(m_pressure.getValue())
|
|
|
|
|
? computeThickness(pressureValue, m_rasThickness) * 2
|
|
|
|
|
: maxThick;
|
|
|
|
|
|
|
|
|
|
if (m_pressure.getValue() && pressureValue == 1.0)
|
|
|
|
|
thickness = m_rasThickness.getValue().first;
|
|
|
|
|
|
2023-02-04 15:05:42 +13:00
|
|
|
|
m_cmRasterBrush->add(TThickPoint(
|
2016-06-15 18:43:10 +12:00
|
|
|
|
m_mousePos + convert(ti->getRaster()->getCenter()), thickness));
|
2023-02-04 15:05:42 +13:00
|
|
|
|
m_tileSaver->save(m_cmRasterBrush->getLastRect());
|
|
|
|
|
m_cmRasterBrush->generateLastPieceOfStroke(true, true);
|
2016-06-15 18:43:10 +12:00
|
|
|
|
|
|
|
|
|
TTool::Application *app = TTool::getApplication();
|
|
|
|
|
TXshLevel *level = app->getCurrentLevel()->getLevel();
|
|
|
|
|
TXshSimpleLevelP simLevel = level->getSimpleLevel();
|
|
|
|
|
|
|
|
|
|
/*-- 描画中にフレームが動いても、描画開始時のFidに対してUndoを記録する
|
|
|
|
|
* --*/
|
|
|
|
|
TFrameId frameId =
|
|
|
|
|
m_workingFrameId.isEmptyFrame() ? getCurrentFid() : m_workingFrameId;
|
|
|
|
|
|
2023-02-04 15:05:42 +13:00
|
|
|
|
double symmetryLines = 0;
|
|
|
|
|
double rotation = 0;
|
|
|
|
|
bool useLineSymmetry = false;
|
|
|
|
|
TPointD centerPoint(0, 0);
|
|
|
|
|
SymmetryTool *symmetryTool = dynamic_cast<SymmetryTool *>(
|
|
|
|
|
TTool::getTool("T_Symmetry", TTool::RasterImage));
|
|
|
|
|
if (symmetryTool && symmetryTool->isGuideEnabled()) {
|
|
|
|
|
SymmetryObject symmObj = symmetryTool->getSymmetryObject();
|
|
|
|
|
symmetryLines = symmObj.getLines();
|
|
|
|
|
rotation = symmObj.getRotation();
|
|
|
|
|
centerPoint = symmObj.getCenterPoint();
|
|
|
|
|
useLineSymmetry = symmObj.isUsingLineSymmetry();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TPointD dpiScale = getViewer()->getDpiScale();
|
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
|
TUndoManager::manager()->add(new BrushUndo(
|
2023-02-04 15:05:42 +13:00
|
|
|
|
m_tileSaver->getTileSet(), m_cmRasterBrush->getPointsSequence(true),
|
|
|
|
|
m_colorTypeBrush, m_cmRasterBrush->getStyleId(),
|
|
|
|
|
m_cmRasterBrush->isSelective(), simLevel.getPointer(), frameId,
|
|
|
|
|
m_cmRasterBrush->isAlphaLocked(), dpiScale, symmetryLines, rotation,
|
|
|
|
|
centerPoint, useLineSymmetry));
|
2016-06-15 18:43:10 +12:00
|
|
|
|
ToolUtils::updateSaveBox();
|
|
|
|
|
|
|
|
|
|
/*--- FIdを指定して、描画中にフレームが変わっても、
|
|
|
|
|
クリック時のFidのサムネイルが更新されるようにする。---*/
|
|
|
|
|
notifyImageChanged(frameId);
|
|
|
|
|
|
|
|
|
|
invalidate();
|
2023-02-04 15:05:42 +13:00
|
|
|
|
delete m_cmRasterBrush;
|
|
|
|
|
m_cmRasterBrush = 0;
|
2016-06-15 18:43:10 +12:00
|
|
|
|
delete m_tileSaver;
|
|
|
|
|
|
|
|
|
|
/*--- 作業中のフレームをリセット ---*/
|
|
|
|
|
m_workingFrameId = TFrameId();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ToolUtils::updateSaveBox();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_selecting = false;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
}
|
2021-06-03 07:42:54 +12:00
|
|
|
|
|
|
|
|
|
int PaintBrushTool::getStyleUnderCursor(const TPointD &pos) {
|
|
|
|
|
int modeValue = 2; // Stylepicker modes: 0=AREAS, 1=LINES, 2=ALL
|
|
|
|
|
|
|
|
|
|
TImageP image = getImage(false);
|
|
|
|
|
TToonzImageP ti = image;
|
|
|
|
|
TXshSimpleLevel *level =
|
|
|
|
|
getApplication()->getCurrentLevel()->getSimpleLevel();
|
|
|
|
|
if (!ti || !level) return -1;
|
|
|
|
|
|
|
|
|
|
if (!m_viewer->getGeometry().contains(pos)) return -1;
|
|
|
|
|
|
|
|
|
|
int subsampling = level->getImageSubsampling(getCurrentFid());
|
|
|
|
|
|
2022-02-28 11:18:09 +13:00
|
|
|
|
StylePicker picker(getViewer()->viewerWidget(), image);
|
2021-06-03 07:42:54 +12:00
|
|
|
|
|
|
|
|
|
int styleId =
|
|
|
|
|
picker.pickStyleId(TScale(1.0 / subsampling) * pos,
|
|
|
|
|
getPixelSize() * getPixelSize(), 1.0, modeValue);
|
|
|
|
|
|
|
|
|
|
if (styleId <= 0) return -1;
|
|
|
|
|
|
|
|
|
|
return styleId;
|
|
|
|
|
}
|