diff --git a/toonz/sources/tnztools/bluredbrush.cpp b/toonz/sources/tnztools/bluredbrush.cpp index 44f5214..61ee125 100644 --- a/toonz/sources/tnztools/bluredbrush.cpp +++ b/toonz/sources/tnztools/bluredbrush.cpp @@ -197,7 +197,14 @@ BluredBrush::~BluredBrush() {} //---------------------------------------------------------------------------------- -void BluredBrush::addPoint(const TThickPoint &p, double opacity) { +void BluredBrush::addPoint(const TThickPoint &p, double opacity, bool keepDistance) { + if (keepDistance) { + double dist = norm2(p - m_lastPoint); + double d = 0.12 * m_lastPoint.thick; + if (dist < d*d) + return; + } + double radius = p.thick * 0.5; double brushRadius = m_size * 0.5; double scaleFactor = radius / brushRadius; diff --git a/toonz/sources/tnztools/bluredbrush.h b/toonz/sources/tnztools/bluredbrush.h index 3f7a32c..650a001 100644 --- a/toonz/sources/tnztools/bluredbrush.h +++ b/toonz/sources/tnztools/bluredbrush.h @@ -34,7 +34,7 @@ public: bool doDynamicOpacity); ~BluredBrush(); - void addPoint(const TThickPoint &p, double opacity); + void addPoint(const TThickPoint &p, double opacity, bool keepDistance = false); void addArc(const TThickPoint &pa, const TThickPoint &pb, const TThickPoint &pc, double opacityA, double opacityC); TRect getBoundFromPoints(const std::vector &points) const; diff --git a/toonz/sources/tnztools/toonzrasterbrushtool.cpp b/toonz/sources/tnztools/toonzrasterbrushtool.cpp index b10a4ef..2d30c40 100644 --- a/toonz/sources/tnztools/toonzrasterbrushtool.cpp +++ b/toonz/sources/tnztools/toonzrasterbrushtool.cpp @@ -6,7 +6,6 @@ #include "tools/toolhandle.h" #include "tools/toolutils.h" #include "tools/tooloptions.h" -#include "bluredbrush.h" // TnzQt includes #include "toonzqt/dvdialog.h" @@ -21,7 +20,6 @@ #include "toonz/txsheet.h" #include "toonz/tstageobject.h" #include "toonz/tstageobjectspline.h" -#include "toonz/rasterstrokegenerator.h" #include "toonz/ttileset.h" #include "toonz/txshsimplelevel.h" #include "toonz/toonzimageutils.h" @@ -884,7 +882,6 @@ ToonzRasterBrushTool::ToonzRasterBrushTool(std::string name, int targetType) , m_isPrompting(false) , m_firstTime(true) , m_presetsLoaded(false) - , m_workingFrameId(TFrameId()) , m_notifier(0) { bind(targetType); @@ -912,6 +909,18 @@ ToonzRasterBrushTool::ToonzRasterBrushTool(std::string name, int targetType) m_preset.addValue(CUSTOM_WSTR); m_pressure.setId("PressureSensitivity"); m_modifierLockAlpha.setId("LockAlpha"); + + m_inputmanager.setHandler(this); +#ifndef NDEBUG + m_modifierTest = new TModifierTest(5, 40); +#endif + m_modifierLine = new TModifierLine(); + m_modifierTangents = new TModifierTangents(); + m_modifierAssistants = new TModifierAssistants(); + m_modifierSegmentation = new TModifierSegmentation(); + + m_inputmanager.addModifier( + TInputModifierP(m_modifierAssistants.getPointer())); } //------------------------------------------------------------------------------------------------------- @@ -1110,70 +1119,6 @@ void ToonzRasterBrushTool::updateTranslation() { //--------------------------------------------------------------------------------------------------- -void ToonzRasterBrushTool::updateWorkAndBackupRasters(const TRect &rect) { - TToonzImageP ti = TImageP(getImage(false, 1)); - if (!ti) return; - - TRasterCM32P ras = ti->getRaster(); - - if (m_isMyPaintStyleSelected) { - const int denominator = 8; - TRect enlargedRect = rect + m_painting.lastRect; - int dx = (enlargedRect.getLx() - 1) / denominator + 1; - int dy = (enlargedRect.getLy() - 1) / denominator + 1; - - if (m_painting.lastRect.isEmpty()) { - enlargedRect.x0 -= dx; - enlargedRect.y0 -= dy; - enlargedRect.x1 += dx; - enlargedRect.y1 += dy; - - TRect _rect = enlargedRect * ras->getBounds(); - if (_rect.isEmpty()) return; - - m_workRas->extract(_rect)->copy(ras->extract(_rect)); - m_backupRas->extract(_rect)->copy(ras->extract(_rect)); - } else { - if (enlargedRect.x0 < m_painting.lastRect.x0) enlargedRect.x0 -= dx; - if (enlargedRect.y0 < m_painting.lastRect.y0) enlargedRect.y0 -= dy; - if (enlargedRect.x1 > m_painting.lastRect.x1) enlargedRect.x1 += dx; - if (enlargedRect.y1 > m_painting.lastRect.y1) enlargedRect.y1 += dy; - - TRect _rect = enlargedRect * ras->getBounds(); - if (_rect.isEmpty()) return; - - TRect _lastRect = m_painting.lastRect * ras->getBounds(); - QList rects = ToolUtils::splitRect(_rect, _lastRect); - for (int i = 0; i < rects.size(); i++) { - m_workRas->extract(rects[i])->copy(ras->extract(rects[i])); - m_backupRas->extract(rects[i])->copy(ras->extract(rects[i])); - } - } - - m_painting.lastRect = enlargedRect; - return; - } - - TRect _rect = rect * ras->getBounds(); - TRect _lastRect = m_painting.lastRect * ras->getBounds(); - - if (_rect.isEmpty()) return; - - if (m_painting.lastRect.isEmpty()) { - m_workRas->extract(_rect)->clear(); - m_backupRas->extract(_rect)->copy(ras->extract(_rect)); - return; - } - - QList rects = ToolUtils::splitRect(_rect, _lastRect); - for (int i = 0; i < rects.size(); i++) { - m_workRas->extract(rects[i])->clear(); - m_backupRas->extract(rects[i])->copy(ras->extract(rects[i])); - } -} - -//--------------------------------------------------------------------------------------------------- - void ToonzRasterBrushTool::onActivate() { if (!m_notifier) m_notifier = new ToonzRasterBrushToolNotifier(this); @@ -1202,18 +1147,8 @@ void ToonzRasterBrushTool::onActivate() { //-------------------------------------------------------------------------------------------------- void ToonzRasterBrushTool::onDeactivate() { - /*--- - * ドラッグ中にツールが切り替わった場合に備え、onDeactivateにもMouseReleaseと同じ処理を行う - * ---*/ - if (m_painting.tileSaver) { - bool isValid = m_enabled && m_painting.active; - m_enabled = false; - m_painting.active = false; - if (isValid) { - finishRasterBrush(m_mousePos, - 1); /*-- 最後のストロークの筆圧は1とする --*/ - } - } + m_inputmanager.finishTracks(); + m_enabled = false; m_workRas = TRaster32P(); m_backupRas = TRasterCM32P(); } @@ -1226,7 +1161,6 @@ bool ToonzRasterBrushTool::askRead(const TRect &rect) { return askWrite(rect); } bool ToonzRasterBrushTool::askWrite(const TRect &rect) { if (rect.isEmpty()) return true; - m_painting.myPaint.strokeRect += rect; m_painting.myPaint.strokeSegmentRect += rect; updateWorkAndBackupRasters(rect); m_painting.tileSaver->save(rect); @@ -1236,6 +1170,17 @@ bool ToonzRasterBrushTool::askWrite(const TRect &rect) { //-------------------------------------------------------------------------------------------------- bool ToonzRasterBrushTool::preLeftButtonDown() { + m_modifierAssistants->drawOnly = true; + m_inputmanager.drawPreview = false; //! m_modifierAssistants->drawOnly; + + m_inputmanager.clearModifiers(); + m_inputmanager.addModifier(TInputModifierP(m_modifierTangents.getPointer())); + m_inputmanager.addModifier(TInputModifierP(m_modifierAssistants.getPointer())); + m_inputmanager.addModifier(TInputModifierP(m_modifierSegmentation.getPointer())); +#ifndef NDEBUG + m_inputmanager.addModifier(TInputModifierP(m_modifierTest.getPointer())); +#endif + touchImage(); if (m_isFrameCreated) { setWorkAndBackupImages(); @@ -1247,635 +1192,337 @@ bool ToonzRasterBrushTool::preLeftButtonDown() { return true; } -//-------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------- -void ToonzRasterBrushTool::leftButtonDown(const TPointD &pos, +void ToonzRasterBrushTool::handleMouseEvent(MouseEventType type, + const TPointD &pos, const TMouseEvent &e) { - TTool::Application *app = TTool::getApplication(); - if (!app) return; - - int col = app->getCurrentColumn()->getColumnIndex(); - m_enabled = col >= 0 || app->getCurrentFrame()->isEditingLevel(); - // todo: gestire autoenable - if (!m_enabled) return; - - m_painting.active = !!getImage(true); - if (!m_painting.active) m_painting.active = !!touchImage(); - if (!m_painting.active) return; - - // nel caso che il colore corrente sia un cleanup/studiopalette color - // oppure il colore di un colorfield - if (TColorStyle *cs = app->getCurrentLevelStyle()) { - m_painting.styleId = app->getCurrentLevelStyleIndex(); - TRasterStyleFx *rfx = cs->getRasterStyleFx(); - if (!cs->isStrokeStyle() && (!rfx || !rfx->isInkStyle())) - { m_painting.active = false; return; } - } else { - m_painting.styleId = 1; - } - - TPointD centeredPos = getCenteredCursorPos(pos); - - // Modifier to do straight line - if (e.isShiftPressed()) { - m_painting.straight.isStraight = true; - m_painting.straight.firstPoint = pos; - m_painting.straight.lastPoint = pos; + TTimerTicks t = TToolTimer::ticks(); + bool alt = e.getModifiersMask() & TMouseEvent::ALT_KEY; + bool shift = e.getModifiersMask() & TMouseEvent::SHIFT_KEY; + bool control = e.getModifiersMask() & TMouseEvent::CTRL_KEY; + + if (shift && type == ME_DOWN && e.button() == Qt::LeftButton && !m_painting.active) { + m_modifierAssistants->drawOnly = true; + m_inputmanager.clearModifiers(); + m_inputmanager.addModifier(TInputModifierP(m_modifierLine.getPointer())); + m_inputmanager.addModifier(TInputModifierP(m_modifierAssistants.getPointer())); + m_inputmanager.addModifier(TInputModifierP(m_modifierSegmentation.getPointer())); + m_inputmanager.drawPreview = true; } - double pressure; - if (m_isMyPaintStyleSelected) // mypaint brush case - pressure = m_pressure.getValue() && e.isTablet() ? e.m_pressure : 0.5; - else - pressure = m_pressure.getValue() ? e.m_pressure : 1.0; - - TImageP img = getImage(true); - TToonzImageP ri(img); - TRasterCM32P ras = ri->getRaster(); - if (ras) { - TPointD rasCenter = ras->getCenterD(); - m_painting.tileSet = new TTileSetCM32(ras->getSize()); - m_painting.tileSaver = new TTileSaverCM32(ras, m_painting.tileSet); - double maxThick = m_rasThickness.getValue().second; - double thickness = (m_pressure.getValue()) - ? computeThickness(pressure, m_rasThickness) * 2 - : maxThick; - - /*--- ストロークの最初にMaxサイズの円が描かれてしまう不具合を防止する - * ---*/ - if (m_pressure.getValue() && e.m_pressure == 1.0 && !m_painting.straight.isStraight) - thickness = m_rasThickness.getValue().first; - - TPointD halfThick(maxThick * 0.5, maxThick * 0.5); - TRectD invalidateRect(centeredPos - halfThick, centeredPos + halfThick); - TPointD dpi; - ri->getDpi(dpi.x, dpi.y); - TRectD previousTipRect(m_brushPos - halfThick, m_brushPos + halfThick); - if (dpi.x > Stage::inch || dpi.y > Stage::inch) - previousTipRect *= dpi.x / Stage::inch; - invalidateRect += previousTipRect; - - // if the drawOrder mode = "Palette Order", - // get styleId list which is above the current style in the palette - DrawOrder drawOrder = (DrawOrder)m_drawOrder.getIndex(); - QSet aboveStyleIds; - if (drawOrder == PaletteOrder) { - getAboveStyleIdSet(m_painting.styleId, ri->getPalette(), aboveStyleIds); - } - - // mypaint brush case - if (m_isMyPaintStyleSelected) { - TPointD point(centeredPos + rasCenter); - - updateCurrentStyle(); - if (!(m_workRas && m_backupRas)) setWorkAndBackupImages(); - m_workRas->lock(); - mypaint::Brush mypaintBrush; - TMyPaintBrushStyle *mypaintStyle = - dynamic_cast(app->getCurrentLevelStyle()); - { // applyToonzBrushSettings - mypaintBrush.fromBrush(mypaintStyle->getBrush()); - double modifierSize = m_modifierSize.getValue() * log(2.0); - float baseSize = - mypaintBrush.getBaseValue(MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC); - mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC, - baseSize + modifierSize); - } - m_painting.myPaint.brush = new MyPaintToonzBrush(m_workRas, *this, mypaintBrush); - m_painting.myPaint.strokeRect.empty(); - m_painting.myPaint.strokeSegmentRect.empty(); - m_painting.myPaint.brush->beginStroke(); - m_painting.myPaint.brush->strokeTo(point, pressure, TPointD(), restartBrushTimer()); - TRect updateRect = m_painting.myPaint.strokeSegmentRect * ras->getBounds(); - if (!updateRect.isEmpty()) { - m_painting.myPaint.brush->updateDrawing( ri->getRaster(), m_backupRas, m_painting.myPaint.strokeRect, - m_painting.styleId, m_modifierLockAlpha.getValue() ); - } - m_painting.lastRect = m_painting.myPaint.strokeRect; - - TPointD thickOffset(m_maxCursorThick * 0.5, m_maxCursorThick * 0.5); - invalidateRect = convert(m_painting.myPaint.strokeSegmentRect) - rasCenter; - invalidateRect += - TRectD(centeredPos - thickOffset, centeredPos + thickOffset); - invalidateRect += - TRectD(m_brushPos - thickOffset, m_brushPos + thickOffset); - } else if (m_hardness.getValue() == 100 || m_pencil.getValue()) { - m_painting.pencil.realPencil = m_pencil.getValue(); - - /*-- Pencilモードでなく、Hardness=100 の場合のブラシサイズを1段階下げる - * --*/ - if (!m_painting.pencil.realPencil && !m_painting.straight.isStraight) thickness -= 1.0; - - TThickPoint thickPoint(centeredPos + convert(ras->getCenter()), - thickness); - m_painting.pencil.brush = new RasterStrokeGenerator( - ras, BRUSH, NONE, m_painting.styleId, thickPoint, drawOrder != OverAll, 0, - m_modifierLockAlpha.getValue(), !m_painting.pencil.realPencil, - drawOrder == PaletteOrder); - - if (drawOrder == PaletteOrder) - m_painting.pencil.brush->setAboveStyleIds(aboveStyleIds); - - m_painting.tileSaver->save( m_painting.pencil.brush->getLastRect() ); - if (!m_painting.straight.isStraight) - m_painting.pencil.brush->generateLastPieceOfStroke( m_painting.pencil.realPencil ); - - m_painting.smooth = m_smooth.getValue() > 0; - if (m_painting.smooth) { - std::vector pts; - m_painting.smoothStroke.beginStroke(m_smooth.getValue()); - m_painting.smoothStroke.addPoint(thickPoint); - m_painting.smoothStroke.getSmoothPoints(pts); - } - } else { - m_painting.blured.points.clear(); - TThickPoint point(centeredPos + rasCenter, thickness); - m_painting.blured.points.push_back(point); - m_painting.blured.brush = new BluredBrush(m_workRas, maxThick, m_brushPad, false); - - if (drawOrder == PaletteOrder) - m_painting.blured.brush->setAboveStyleIds(aboveStyleIds); - - TRect strokeRect = m_painting.blured.brush->getBoundFromPoints( m_painting.blured.points ); - updateWorkAndBackupRasters(strokeRect); - m_painting.tileSaver->save(strokeRect); - m_painting.blured.brush->addPoint(point, 1); - if (!m_painting.straight.isStraight) - m_painting.blured.brush->updateDrawing( ri->getRaster(), m_backupRas, strokeRect, - m_painting.styleId, drawOrder, - m_modifierLockAlpha.getValue() ); - m_painting.lastRect = strokeRect; - - m_painting.smooth = m_smooth.getValue() > 0; - if (m_painting.smooth) { - std::vector pts; - m_painting.smoothStroke.beginStroke(m_smooth.getValue()); - m_painting.smoothStroke.addPoint(point); - m_painting.smoothStroke.getSmoothPoints(pts); - } - } - /*-- 作業中のFidを登録 --*/ - m_workingFrameId = getFrameId(); + if (alt != m_inputmanager.state.isKeyPressed(TKey::alt)) + m_inputmanager.keyEvent(alt, TKey::alt, t, nullptr); + if (shift != m_inputmanager.state.isKeyPressed(TKey::shift)) + m_inputmanager.keyEvent(shift, TKey::shift, t, nullptr); + if (control != m_inputmanager.state.isKeyPressed(TKey::control)) + m_inputmanager.keyEvent(control, TKey::control, t, nullptr); - invalidate(invalidateRect.enlarge(2)); + if (type == ME_MOVE) { + THoverList hovers(1, pos); + m_inputmanager.hoverEvent(hovers); + } else { + m_inputmanager.trackEvent(e.isTablet(), 0, pos, + e.isTablet() ? &e.m_pressure : nullptr, nullptr, + type == ME_UP, t); + m_inputmanager.processTracks(); } - // updating m_brushPos is needed to refresh viewer properly - m_mousePos = pos; - m_brushPos = getCenteredCursorPos(pos); } -//------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------- +void ToonzRasterBrushTool::leftButtonDown(const TPointD &pos, + const TMouseEvent &e) { + handleMouseEvent(ME_DOWN, pos, e); +} void ToonzRasterBrushTool::leftButtonDrag(const TPointD &pos, - const TMouseEvent &e) { - TRectD invalidateRect; - m_painting.straight.lastPoint = pos; - - if (!m_enabled || !m_painting.active) { - m_mousePos = pos; - m_brushPos = getCenteredCursorPos(pos); - return; - } - - TPointD centeredPos = getCenteredCursorPos(m_painting.straight.lastPoint); - - double pressure; - if (m_isMyPaintStyleSelected) // mypaint brush case - pressure = m_pressure.getValue() && e.isTablet() ? e.m_pressure : 0.5; - else - pressure = m_pressure.getValue() ? e.m_pressure : 1.0; - - TToonzImageP ti = TImageP(getImage(true)); - TPointD rasCenter = ti->getRaster()->getCenterD(); - double maxThickness = m_rasThickness.getValue().second; - double thickness = (m_pressure.getValue()) - ? computeThickness(pressure, m_rasThickness) * 2 - : maxThickness; + const TMouseEvent &e) { + handleMouseEvent(ME_DRAG, pos, e); +} +void ToonzRasterBrushTool::leftButtonUp(const TPointD &pos, + const TMouseEvent &e) { + handleMouseEvent(ME_UP, pos, e); +} +void ToonzRasterBrushTool::mouseMove(const TPointD &pos, const TMouseEvent &e) { + handleMouseEvent(ME_MOVE, pos, e); +} - if (m_painting.straight.maxPressure < pressure) m_painting.straight.maxPressure = pressure; +//-------------------------------------------------------------------------------------------------- - if (m_painting.straight.isStraight) { - invalidateRect = TRectD(m_painting.straight.firstPoint, m_painting.straight.lastPoint).enlarge(2); - 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_painting.straight.lastPoint.x - m_painting.straight.firstPoint.x; - if (denominator == 0) denominator == 0.001; - double slope = ((m_painting.straight.lastPoint.y - m_painting.straight.firstPoint.y) / denominator); - double angle = std::atan(slope) * (180 / 3.14159); - if (abs(angle) > 67.5) - m_painting.straight.lastPoint.x = m_painting.straight.firstPoint.x; - else if (abs(angle) < 22.5) - m_painting.straight.lastPoint.y = m_painting.straight.firstPoint.y; - else { - double xDistance = m_painting.straight.lastPoint.x - m_painting.straight.firstPoint.x; - double yDistance = m_painting.straight.lastPoint.y - m_painting.straight.firstPoint.y; - if (abs(xDistance) > abs(yDistance)) { - if (abs(yDistance) == yDistance) - m_painting.straight.lastPoint.y = m_painting.straight.firstPoint.y + abs(xDistance); - else - m_painting.straight.lastPoint.y = m_painting.straight.firstPoint.y - abs(xDistance); - } else { - if (abs(xDistance) == xDistance) - m_painting.straight.lastPoint.x = m_painting.straight.firstPoint.x + abs(yDistance); - else - m_painting.straight.lastPoint.x = m_painting.straight.firstPoint.x - abs(yDistance); - } - } - } - m_mousePos = pos; - m_brushPos = getCenteredCursorPos(pos); - invalidate(invalidateRect); +void ToonzRasterBrushTool::inputSetBusy(bool busy) { + if (m_painting.active == busy) return; - } - - if (m_painting.myPaint.brush) { - TRasterP ras = ti->getRaster(); - TPointD point(centeredPos + rasCenter); + + if (busy) { + // begin painting + + TTool::Application *app = TTool::getApplication(); + if (!app) return; - m_painting.myPaint.strokeSegmentRect.empty(); - m_painting.myPaint.brush->strokeTo(point, pressure, TPointD(), restartBrushTimer()); - TRect updateRect = m_painting.myPaint.strokeSegmentRect * ras->getBounds(); - if (!updateRect.isEmpty()) { - m_painting.myPaint.brush->updateDrawing( ras, m_backupRas, m_painting.myPaint.strokeSegmentRect, - m_painting.styleId, m_modifierLockAlpha.getValue() ); - } - m_painting.lastRect = m_painting.myPaint.strokeRect; - - TPointD thickOffset(m_maxCursorThick * 0.5, m_maxCursorThick * 0.5); - invalidateRect = convert(m_painting.myPaint.strokeSegmentRect) - rasCenter; - invalidateRect += - TRectD(centeredPos - thickOffset, centeredPos + thickOffset); - invalidateRect += - TRectD(m_brushPos - thickOffset, m_brushPos + thickOffset); - } else - if (m_painting.pencil.brush) { - /*-- Pencilモードでなく、Hardness=100 の場合のブラシサイズを1段階下げる - * --*/ - if (!m_painting.pencil.realPencil) thickness -= 1.0; + int col = app->getCurrentColumn()->getColumnIndex(); + m_enabled = col >= 0 || app->getCurrentFrame()->isEditingLevel(); + // todo: gestire autoenable + if (!m_enabled) return; - TThickPoint thickPoint(centeredPos + rasCenter, thickness); - std::vector pts; - if (m_painting.smooth) { - pts.push_back(thickPoint); + m_painting.active = !!getImage(true); + if (!m_painting.active) + m_painting.active = !!touchImage(); + if (!m_painting.active) + return; + + // nel caso che il colore corrente sia un cleanup/studiopalette color + // oppure il colore di un colorfield + updateCurrentStyle(); + if (TColorStyle *cs = app->getCurrentLevelStyle()) { + m_painting.styleId = app->getCurrentLevelStyleIndex(); + TRasterStyleFx *rfx = cs->getRasterStyleFx(); + if (!cs->isStrokeStyle() && (!rfx || !rfx->isInkStyle())) + { m_painting.active = false; return; } } else { - m_painting.smoothStroke.addPoint(thickPoint); - m_painting.smoothStroke.getSmoothPoints(pts); + m_painting.styleId = 1; } - for (size_t i = 0; i < pts.size(); ++i) { - const TThickPoint &thickPoint = pts[i]; - m_painting.pencil.brush->add( thickPoint); - m_painting.tileSaver->save( m_painting.pencil.brush->getLastRect() ); - m_painting.pencil.brush->generateLastPieceOfStroke( m_painting.pencil.realPencil ); - std::vector brushPoints = m_painting.pencil.brush->getPointsSequence(); - int m = (int)brushPoints.size(); - std::vector points; - if (m == 3) { - points.push_back(brushPoints[0]); - points.push_back(brushPoints[1]); - } else { - points.push_back(brushPoints[m - 4]); - points.push_back(brushPoints[m - 3]); - points.push_back(brushPoints[m - 2]); - } - invalidateRect += ToolUtils::getBounds(points, maxThickness) - rasCenter; - } - } else { - // antialiased brush - assert(m_painting.blured.brush); - assert(m_workRas.getPointer() && m_backupRas.getPointer()); - TThickPoint thickPoint(centeredPos + rasCenter, thickness); - std::vector pts; - if (m_painting.smooth) { - pts.push_back(thickPoint); + + m_painting.frameId = getFrameId(); + + TImageP img = getImage(true); + TToonzImageP ri(img); + TRasterCM32P ras = ri->getRaster(); + if (!ras) + { m_painting.active = false; return; } + + m_painting.tileSet = new TTileSetCM32(ras->getSize()); + m_painting.tileSaver = new TTileSaverCM32(ras, m_painting.tileSet); + m_painting.affectedRect.empty(); + setWorkAndBackupImages(); + + if (m_isMyPaintStyleSelected) { + // init myPaint drawing + + m_painting.myPaint.isActive = true; + m_painting.myPaint.strokeSegmentRect.empty(); + + m_workRas->lock(); + + // prepare base brush + if ( TMyPaintBrushStyle *mypaintStyle = dynamic_cast(app->getCurrentLevelStyle()) ) + m_painting.myPaint.baseBrush.fromBrush( mypaintStyle->getBrush() ); else + m_painting.myPaint.baseBrush.fromDefaults(); + double modifierSize = m_modifierSize.getValue() * log(2.0); + float baseSize = m_painting.myPaint.baseBrush.getBaseValue( MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC ); + m_painting.myPaint.baseBrush.setBaseValue( MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC, baseSize + modifierSize ); + } else + if (m_hardness.getValue() == 100 || m_pencil.getValue()) { + // init pencil drawing + + m_painting.pencil.isActive = true; + m_painting.pencil.realPencil = m_pencil.getValue(); } else { - m_painting.smoothStroke.addPoint(thickPoint); - m_painting.smoothStroke.getSmoothPoints(pts); + // init blured brush drawing (regular drawing) + + m_painting.blured.isActive = true; } - for (size_t i = 0; i < pts.size(); ++i) { - TThickPoint old = m_painting.blured.points.back(); - - const TThickPoint &point = pts[i]; - TThickPoint mid((old + point) * 0.5, (point.thick + old.thick) * 0.5); - m_painting.blured.points.push_back(mid); - m_painting.blured.points.push_back(point); - - TRect bbox; - int m = (int)m_painting.blured.points.size(); - std::vector points; - if (m == 3) { - // ho appena cominciato. devo disegnare un segmento - TThickPoint pa = m_painting.blured.points.front(); - points.push_back(pa); - points.push_back(mid); - bbox = m_painting.blured.brush->getBoundFromPoints(points); - updateWorkAndBackupRasters(bbox + m_painting.lastRect); - m_painting.tileSaver->save(bbox); - m_painting.blured.brush->addArc(pa, (mid + pa) * 0.5, mid, 1, 1); - m_painting.lastRect += bbox; - } else { - points.push_back(m_painting.blured.points[m - 4]); - points.push_back(old); - points.push_back(mid); - bbox = m_painting.blured.brush->getBoundFromPoints(points); - updateWorkAndBackupRasters(bbox + m_painting.lastRect); - m_painting.tileSaver->save(bbox); - m_painting.blured.brush->addArc( m_painting.blured.points[m - 4], old, mid, 1, 1 ); - m_painting.lastRect += bbox; - } - invalidateRect += ToolUtils::getBounds(points, maxThickness) - rasCenter; - - m_painting.blured.brush->updateDrawing( ti->getRaster(), m_backupRas, bbox, - m_painting.styleId, m_drawOrder.getIndex(), - m_modifierLockAlpha.getValue() ); + + } else { + // finish painting + + if (m_painting.myPaint.isActive) { + // finish myPaint drawing + m_workRas->unlock(); } - } - // clear & draw brush tip when drawing smooth stroke - if (m_painting.smooth) { - TPointD halfThick(m_maxThick * 0.5, m_maxThick * 0.5); - invalidateRect += TRectD(m_brushPos - halfThick, m_brushPos + halfThick); - invalidateRect += TRectD(centeredPos - halfThick, centeredPos + halfThick); - } + delete m_painting.tileSaver; + m_painting.tileSaver = nullptr; - m_mousePos = pos; - m_brushPos = getCenteredCursorPos(pos); + // add undo record + TFrameId frameId = m_painting.frameId.isEmptyFrame() ? getCurrentFid() : m_painting.frameId; + if (m_painting.tileSet->getTileCount() > 0) { + TTool::Application *app = TTool::getApplication(); + TXshLevel *level = app->getCurrentLevel()->getLevel(); + TXshSimpleLevelP simLevel = level->getSimpleLevel(); + TRasterCM32P ras = TToonzImageP( getImage(true) )->getRaster(); + TRasterCM32P subras = ras->extract(m_painting.affectedRect)->clone(); + TUndoManager::manager()->add(new MyPaintBrushUndo( + m_painting.tileSet, simLevel.getPointer(), frameId, m_isFrameCreated, + m_isLevelCreated, subras, m_painting.affectedRect.getP00())); + // MyPaintBrushUndo will delete tileSet by it self + } else { + // delete tileSet here because MyPaintBrushUndo will not do it + delete m_painting.tileSet; + } + m_painting.tileSet = nullptr; - invalidate(invalidateRect.enlarge(2)); -} + /*-- 作業中のフレームをリセット --*/ + m_painting.frameId = TFrameId(); -//--------------------------------------------------------------------------------------------------------------- -void ToonzRasterBrushTool::leftButtonUp(const TPointD &pos, - const TMouseEvent &e) { - bool isValid = m_enabled && m_painting.active; - m_enabled = false; - m_painting.active = false; - if (!isValid) { - return; + m_painting.myPaint.isActive = false; + m_painting.pencil.isActive = false; + m_painting.blured.isActive = false; + m_painting.active = false; + + /*-- FIdを指定して、描画中にフレームが動いても、 + 描画開始時のFidのサムネイルが更新されるようにする。--*/ + notifyImageChanged(frameId); + ToolUtils::updateSaveBox(); } - TPointD centeredPos; - if (m_painting.straight.isStraight) - centeredPos = getCenteredCursorPos(m_painting.straight.lastPoint); - else - centeredPos = getCenteredCursorPos(pos); - - double pressure; - if (m_isMyPaintStyleSelected) // mypaint brush case - pressure = m_pressure.getValue() && e.isTablet() ? e.m_pressure : 0.5; - else - pressure = m_pressure.getValue() ? e.m_pressure : 1.0; - - if (m_painting.straight.isStraight && m_painting.straight.maxPressure > 0.0) pressure = m_painting.straight.maxPressure; - - finishRasterBrush(centeredPos, pressure); - int tc = ToonzCheck::instance()->getChecks(); - if (tc & ToonzCheck::eGap || tc & ToonzCheck::eAutoclose || m_painting.straight.isStraight) - invalidate(); - - m_painting.straight.isStraight = false; - m_painting.straight.maxPressure = -1.0; } -//--------------------------------------------------------------------------------------------------------------- -/*! - * ドラッグ中にツールが切り替わった場合に備え、onDeactivate時とMouseRelease時にと同じ終了処理を行う - */ -void ToonzRasterBrushTool::finishRasterBrush(const TPointD &pos, - double pressureVal) { - TToonzImageP ti = TImageP(getImage(true)); - - if (!ti) return; +//-------------------------------------------------------------------------------------------------- - TPointD rasCenter = ti->getRaster()->getCenterD(); - TTool::Application *app = TTool::getApplication(); - TXshLevel *level = app->getCurrentLevel()->getLevel(); - TXshSimpleLevelP simLevel = level->getSimpleLevel(); - - /*-- - * 描画中にカレントフレームが変わっても、描画開始時のFidに対してUndoを記録する - * --*/ - TFrameId frameId = - m_workingFrameId.isEmptyFrame() ? getCurrentFid() : m_workingFrameId; - if (m_painting.myPaint.brush) { - TRasterCM32P ras = ti->getRaster(); - TPointD point(pos + rasCenter); - double pressure = m_pressure.getValue() ? pressureVal : 0.5; +void ToonzRasterBrushTool::inputPaintTrackPoint(const TTrackPoint &point, const TTrack &track, bool firstTrack) { + if (!m_painting.active) + return; + + TImageP img = getImage(true); + TToonzImageP ri(img); + TRasterCM32P ras = ri->getRaster(); + if (!ras) + return; + TPointD rasCenter = ras->getCenterD(); + + TRectD invalidateRect; + bool firstPoint = track.size() == track.pointsAdded; + bool lastPoint = track.pointsAdded == 1 && track.finished(); + + // first point must be without handler, following points must be with handler + // other behaviour is possible bug and must be ignored + assert(firstPoint == !track.toolHandler); + if (firstPoint != !track.toolHandler) + return; + + if (m_painting.myPaint.isActive) { + // mypaint case + + // init brush + MyPaintStroke *handler; + if (firstPoint) { + handler = new MyPaintStroke(m_workRas, *this, m_painting.myPaint.baseBrush, false); + handler->brush.beginStroke(); + track.toolHandler = handler; + } + handler = dynamic_cast(track.toolHandler.getPointer()); + if (!handler) return; + + // paint stroke m_painting.myPaint.strokeSegmentRect.empty(); - m_painting.myPaint.brush->strokeTo(point, pressure, TPointD(), restartBrushTimer()); - m_painting.myPaint.brush->endStroke(); + handler->brush.strokeTo(point.position + rasCenter, point.pressure, point.tilt, point.time); + if (lastPoint) + handler->brush.endStroke(); + + // update affected area TRect updateRect = m_painting.myPaint.strokeSegmentRect * ras->getBounds(); - if (!updateRect.isEmpty()) { - m_painting.myPaint.brush->updateDrawing( ras, m_backupRas, m_painting.myPaint.strokeSegmentRect, - m_painting.styleId, m_modifierLockAlpha.getValue() ); - } - TPointD thickOffset(m_maxCursorThick * 0.5, - m_maxCursorThick * 0.5); // TODO - TRectD invalidateRect = convert(m_painting.myPaint.strokeSegmentRect) - rasCenter; - invalidateRect += TRectD(pos - thickOffset, pos + thickOffset); - invalidate(invalidateRect.enlarge(2.0)); - - delete m_painting.myPaint.brush; - m_painting.myPaint.brush = nullptr; - - m_painting.lastRect.empty(); - m_workRas->unlock(); - - if (m_painting.tileSet->getTileCount() > 0) { - TRasterCM32P subras = ras->extract(m_painting.myPaint.strokeRect)->clone(); - TUndoManager::manager()->add(new MyPaintBrushUndo( - m_painting.tileSet, simLevel.getPointer(), frameId, m_isFrameCreated, - m_isLevelCreated, subras, m_painting.myPaint.strokeRect.getP00())); - } - + m_painting.affectedRect += updateRect; + if (!updateRect.isEmpty()) + handler->brush.updateDrawing( ras, m_backupRas, m_painting.myPaint.strokeSegmentRect, + m_painting.styleId, m_modifierLockAlpha.getValue() ); + + // determine invalidate rect + invalidateRect += convert(m_painting.myPaint.strokeSegmentRect) - rasCenter; } else - if (m_painting.pencil.brush) { - double thickness = m_pressure.getValue() - ? computeThickness(pressureVal, m_rasThickness) * 2 - : m_rasThickness.getValue().second; - - if (!m_painting.straight.isStraight) { - // ストロークの最初にMaxサイズの円が描かれてしまう不具合を防止する - if (m_pressure.getValue() && pressureVal == 1.0) - thickness = m_rasThickness.getValue().first; - - // Pencilモードでなく、Hardness=100 の場合のブラシサイズを1段階下げる - if (!m_painting.pencil.realPencil) thickness -= 1.0; - } - - TRectD invalidateRect; - TThickPoint thickPoint(pos + rasCenter, thickness); - std::vector pts; - if (m_painting.smooth || m_painting.straight.isStraight) { - pts.push_back(thickPoint); - } else { - m_painting.smoothStroke.addPoint(thickPoint); - m_painting.smoothStroke.endStroke(); - m_painting.smoothStroke.getSmoothPoints(pts); - } - for (size_t i = 0; i < pts.size(); ++i) { - const TThickPoint &thickPoint = pts[i]; - m_painting.pencil.brush->add( thickPoint ); - m_painting.tileSaver->save( m_painting.pencil.brush->getLastRect( m_painting.straight.isStraight) ); - m_painting.pencil.brush->generateLastPieceOfStroke( - m_painting.pencil.realPencil, true, m_painting.straight.isStraight); - - std::vector brushPoints = m_painting.pencil.brush->getPointsSequence(); - int m = (int)brushPoints.size(); - std::vector points; - if (m_painting.straight.isStraight) { - points.push_back(brushPoints[0]); - points.push_back(brushPoints[2]); - } else if (m == 3) { - points.push_back(brushPoints[0]); - points.push_back(brushPoints[1]); - } else { - points.push_back(brushPoints[m - 4]); - points.push_back(brushPoints[m - 3]); - points.push_back(brushPoints[m - 2]); + if (m_painting.pencil.isActive) { + // pencil case + + // Pencilモードでなく、Hardness=100 の場合のブラシサイズを1段階下げる + double thickness = computeThickness(point.pressure, m_rasThickness)*2; + //if (!m_painting.pencil.realPencil && !m_painting.straight.isStraight) + // thickness -= 1.0; + TThickPoint thickPoint(point.position + rasCenter, thickness); + + // init brush + PencilStroke *handler; + if (firstPoint) { + DrawOrder drawOrder = (DrawOrder)m_drawOrder.getIndex(); + handler = new PencilStroke( ras, BRUSH, NONE, m_painting.styleId, thickPoint, drawOrder != OverAll, 0, + m_modifierLockAlpha.getValue(), !m_painting.pencil.realPencil, + drawOrder == PaletteOrder ); + + // if the drawOrder mode = "Palette Order", + // get styleId list which is above the current style in the palette + if (drawOrder == PaletteOrder) { + QSet aboveStyleIds; + getAboveStyleIdSet(m_painting.styleId, ri->getPalette(), aboveStyleIds); + handler->brush.setAboveStyleIds(aboveStyleIds); } - double maxThickness = m_rasThickness.getValue().second; - invalidateRect += ToolUtils::getBounds(points, maxThickness) - rasCenter; - } - invalidate(invalidateRect.enlarge(2)); - - if (m_painting.tileSet->getTileCount() > 0) { - TUndoManager::manager()->add(new RasterBrushUndo( - m_painting.tileSet, m_painting.pencil.brush->getPointsSequence(), - m_painting.pencil.brush->getStyleId(), m_painting.pencil.brush->isSelective(), - simLevel.getPointer(), frameId, m_painting.pencil.realPencil, m_isFrameCreated, - m_isLevelCreated, m_painting.pencil.brush->isPaletteOrder(), - m_painting.pencil.brush->isAlphaLocked(), m_painting.straight.isStraight)); + track.toolHandler = handler; } - delete m_painting.pencil.brush; - m_painting.pencil.brush = nullptr; - } else { - assert(m_painting.blured.brush); - double maxThickness = m_rasThickness.getValue().second; - double thickness = (m_pressure.getValue()) - ? computeThickness(pressureVal, m_rasThickness) * 2 - : maxThickness; - TPointD rasCenter = ti->getRaster()->getCenterD(); - TRectD invalidateRect; - TThickPoint thickPoint(pos + rasCenter, thickness); - std::vector pts; - if (m_painting.smooth || m_painting.straight.isStraight) { - pts.push_back(thickPoint); - } else { - m_painting.smoothStroke.addPoint(thickPoint); - m_painting.smoothStroke.endStroke(); - m_painting.smoothStroke.getSmoothPoints(pts); - } - // we need to skip the for-loop here if pts.size() == 0 or else - // (pts.size() - 1) becomes ULLONG_MAX since size_t is unsigned - if (pts.size() > 0) { - // this doesn't get run for a straight line - for (size_t i = 0; i < pts.size() - 1; ++i) { - TThickPoint old = m_painting.blured.points.back(); - - const TThickPoint &point = pts[i]; - TThickPoint mid((old + point) * 0.5, (point.thick + old.thick) * 0.5); - m_painting.blured.points.push_back(mid); - m_painting.blured.points.push_back(point); - - TRect bbox; - int m = (int)m_painting.blured.points.size(); - std::vector points; - if (m == 3) { - // ho appena cominciato. devo disegnare un segmento - TThickPoint pa = m_painting.blured.points.front(); - points.push_back(pa); - points.push_back(mid); - bbox = m_painting.blured.brush->getBoundFromPoints(points); - updateWorkAndBackupRasters(bbox + m_painting.lastRect); - m_painting.tileSaver->save(bbox); - m_painting.blured.brush->addArc(pa, (mid + pa) * 0.5, mid, 1, 1); - m_painting.lastRect += bbox; - } else { - points.push_back(m_painting.blured.points[m - 4]); - points.push_back(old); - points.push_back(mid); - bbox = m_painting.blured.brush->getBoundFromPoints(points); - updateWorkAndBackupRasters(bbox + m_painting.lastRect); - m_painting.tileSaver->save(bbox); - m_painting.blured.brush->addArc(m_painting.blured.points[m - 4], old, mid, 1, 1); - m_painting.lastRect += bbox; - } - - invalidateRect += - ToolUtils::getBounds(points, maxThickness) - rasCenter; + handler = dynamic_cast(track.toolHandler.getPointer()); + if (!handler) return; + + // paint stroke + if (!firstPoint) + handler->brush.add(thickPoint); + + // update affected area + TRect strokeRect = handler->brush.getLastRect() * ras->getBounds(); + m_painting.tileSaver->save( strokeRect ); + m_painting.affectedRect += strokeRect; + handler->brush.generateLastPieceOfStroke( m_painting.pencil.realPencil ); + + // determine invalidate rect + std::vector points = handler->brush.getPointsSequence(); + int m = (int)points.size() - 3; + if (m > 0) + points.erase(points.begin(), points.begin() + m); + invalidateRect += ToolUtils::getBounds(points, m_rasThickness.getValue().second) - rasCenter; + } else + if (m_painting.blured.isActive) { + // blured brush case (aka regular brush) - m_painting.blured.brush->updateDrawing( ti->getRaster(), m_backupRas, bbox, - m_painting.styleId, m_drawOrder.getIndex(), - m_modifierLockAlpha.getValue() ); - } - if (!m_painting.straight.isStraight && m_painting.blured.points.size() > 1) { - TThickPoint point = pts.back(); - m_painting.blured.points.push_back(point); - } - int m = m_painting.blured.points.size(); - std::vector points; - if (!m_painting.straight.isStraight && m_painting.blured.points.size() > 1) { - points.push_back( m_painting.blured.points[m - 3] ); - points.push_back( m_painting.blured.points[m - 2] ); - points.push_back( m_painting.blured.points[m - 1] ); - } else { - const TThickPoint point = m_painting.blured.points[0]; - TThickPoint mid((thickPoint + point) * 0.5, - (point.thick + thickPoint.thick) * 0.5); - m_painting.blured.points.push_back(mid); - m_painting.blured.points.push_back(thickPoint); - points.push_back( m_painting.blured.points[0] ); - points.push_back( m_painting.blured.points[1] ); - points.push_back( m_painting.blured.points[2] ); + double maxThick = m_rasThickness.getValue().second; + DrawOrder drawOrder = (DrawOrder)m_drawOrder.getIndex(); + + // init brush + BluredStroke *handler; + if (firstPoint) { + handler = new BluredStroke(m_workRas, maxThick, m_brushPad, false); + // if the drawOrder mode = "Palette Order", + // get styleId list which is above the current style in the palette + if (drawOrder == PaletteOrder) { + QSet aboveStyleIds; + getAboveStyleIdSet(m_painting.styleId, ri->getPalette(), aboveStyleIds); + handler->brush.setAboveStyleIds(aboveStyleIds); } - TRect bbox = m_painting.blured.brush->getBoundFromPoints(points); - updateWorkAndBackupRasters(bbox); - m_painting.tileSaver->save(bbox); - m_painting.blured.brush->addArc( points[0], points[1], points[2], 1, 1 ); - m_painting.blured.brush->updateDrawing( ti->getRaster(), m_backupRas, bbox, - m_painting.styleId, m_drawOrder.getIndex(), - m_modifierLockAlpha.getValue() ); - - invalidateRect += ToolUtils::getBounds(points, maxThickness) - rasCenter; - - m_painting.lastRect += bbox; - } - if (!invalidateRect.isEmpty()) invalidate(invalidateRect.enlarge(2)); - m_painting.lastRect.empty(); - - delete m_painting.blured.brush; - m_painting.blured.brush = nullptr; - - if (m_painting.tileSet->getTileCount() > 0) { - TUndoManager::manager()->add(new RasterBluredBrushUndo( - m_painting.tileSet, m_painting.blured.points, m_painting.styleId, (DrawOrder)m_drawOrder.getIndex(), - m_modifierLockAlpha.getValue(), simLevel.getPointer(), frameId, - m_rasThickness.getValue().second, m_hardness.getValue() * 0.01, - m_isFrameCreated, m_isLevelCreated, m_painting.straight.isStraight)); + track.toolHandler = handler; } + handler = dynamic_cast(track.toolHandler.getPointer()); + if (!handler) return; + + // paint stroke + double radius = computeThickness(point.pressure, m_rasThickness); + TThickPoint thickPoint(point.position + rasCenter, radius*2); + TRect strokeRect( tfloor(thickPoint.x - maxThick - 0.999), + tfloor(thickPoint.y - maxThick - 0.999), + tceil(thickPoint.x + maxThick + 0.999), + tceil(thickPoint.y + maxThick + 0.999) ); + strokeRect *= ras->getBounds(); + m_painting.affectedRect += strokeRect; + updateWorkAndBackupRasters(m_painting.affectedRect); + m_painting.tileSaver->save(strokeRect); + handler->brush.addPoint(thickPoint, 1, !lastPoint); + handler->brush.updateDrawing( ras, m_backupRas, strokeRect, + m_painting.styleId, drawOrder, + m_modifierLockAlpha.getValue() ); + + invalidateRect += convert(strokeRect) - rasCenter; } - delete m_painting.tileSaver; - m_painting.tileSaver = nullptr; - - /*-- FIdを指定して、描画中にフレームが動いても、 -   描画開始時のFidのサムネイルが更新されるようにする。--*/ - notifyImageChanged(frameId); - ToolUtils::updateSaveBox(); - - /*-- 作業中のフレームをリセット --*/ - m_workingFrameId = TFrameId(); + // invalidate rect + if (firstTrack) { + // for the first track we will paint cursor circle + // here we will invalidate rects for it + TPointD thickOffset(m_maxCursorThick*0.5, m_maxCursorThick*0.5); + invalidateRect += TRectD(m_brushPos - thickOffset, m_brushPos + thickOffset); + invalidateRect += TRectD(point.position - thickOffset, point.position + thickOffset); + m_brushPos = m_mousePos = point.position; + } + invalidate(invalidateRect.enlarge(2)); } + //--------------------------------------------------------------------------------------------------------------- -// 明日はここをMyPaintのときにカーソルを消せるように修正する!!!!!! -void ToonzRasterBrushTool::mouseMove(const TPointD &pos, const TMouseEvent &e) { - qApp->processEvents(QEventLoop::ExcludeUserInputEvents); +// 明日はここをMyPaintのときにカーソルを消せるように修正する!!!!!! +void ToonzRasterBrushTool::inputMouseMove(const TPointD &position, const TInputState &state) { struct Locals { ToonzRasterBrushTool *m_this; @@ -1914,23 +1561,18 @@ void ToonzRasterBrushTool::mouseMove(const TPointD &pos, const TMouseEvent &e) { } locals = {this}; - // if (e.isAltPressed() && !e.isCtrlPressed()) { - // const TPointD &diff = pos - m_mousePos; - // double add = (fabs(diff.x) > fabs(diff.y)) ? diff.x : diff.y; - - // locals.addMinMax( - // TToonzImageP(getImage(false, 1)) ? m_rasThickness : m_thickness, add); - //} else - double thickness = (m_isMyPaintStyleSelected) ? (double)(m_maxCursorThick + 1) : m_maxThick; TPointD halfThick(thickness * 0.5, thickness * 0.5); TRectD invalidateRect(m_brushPos - halfThick, m_brushPos + halfThick); - if (e.isCtrlPressed() && e.isAltPressed() && !e.isShiftPressed() && - Preferences::instance()->useCtrlAltToResizeBrushEnabled()) { + if ( Preferences::instance()->useCtrlAltToResizeBrushEnabled() + && state.isKeyPressed(TKey::control) + && state.isKeyPressed(TKey::alt) + && !state.isKeyPressed(TKey::shift) ) + { // Resize the brush if CTRL+ALT is pressed and the preference is enabled. - const TPointD &diff = pos - m_mousePos; + const TPointD &diff = position - m_mousePos; double max = diff.x / 2; double min = diff.y / 2; @@ -1941,10 +1583,10 @@ void ToonzRasterBrushTool::mouseMove(const TPointD &pos, const TMouseEvent &e) { m_brushPos + TPointD(radius, radius)); } else { - m_mousePos = pos; - m_brushPos = getCenteredCursorPos(pos); + m_mousePos = position; + m_brushPos = getCenteredCursorPos(position); - invalidateRect += TRectD(pos - halfThick, pos + halfThick); + invalidateRect += TRectD(position - halfThick, position + halfThick); } invalidate(invalidateRect.enlarge(2)); @@ -2005,21 +1647,16 @@ void ToonzRasterBrushTool::draw() { drawEmptyCircle(m_brushPos, tround(m_maxThick), true, true, m_pencil.getValue()); } + + m_inputmanager.draw(); } //-------------------------------------------------------------------------------------------------------------- void ToonzRasterBrushTool::onEnter() { - TImageP img = getImage(false); - m_minThick = m_rasThickness.getValue().first; m_maxThick = m_rasThickness.getValue().second; updateCurrentStyle(); - - Application *app = getApplication(); - - m_painting.styleId = app->getCurrentLevelStyleIndex(); - m_painting.active = img; } //---------------------------------------------------------------------------------------------------------- @@ -2043,7 +1680,6 @@ TPropertyGroup *ToonzRasterBrushTool::getProperties(int idx) { void ToonzRasterBrushTool::onImageChanged() { if (!isEnabled()) return; - setWorkAndBackupImages(); } @@ -2055,22 +1691,57 @@ void ToonzRasterBrushTool::setWorkAndBackupImages() { TRasterP ras = ti->getRaster(); TDimension dim = ras->getSize(); - double hardness = m_hardness.getValue() * 0.01; - if (!m_isMyPaintStyleSelected && hardness == 1.0 && - ras->getPixelSize() == 4) { - m_workRas = TRaster32P(); - m_backupRas = TRasterCM32P(); + if (!m_workRas || m_workRas->getLx() < dim.lx || m_workRas->getLy() < dim.ly) + m_workRas = TRaster32P(dim); + if (!m_backupRas || m_backupRas->getLx() < dim.lx || m_backupRas->getLy() < dim.ly) + m_backupRas = TRasterCM32P(dim); + + m_workBackupRect.empty(); +} + +//--------------------------------------------------------------------------------------------------- + +void ToonzRasterBrushTool::updateWorkAndBackupRasters(const TRect &rect) { + TToonzImageP ti = TImageP(getImage(false, 1)); + if (!ti) return; + TRasterCM32P ras = ti->getRaster(); + + // work and backup rect will additionaly enlarged to 1/8 of it size + // in each affected direction to predict future possible enlargements in this direction + const int denominator = 8; + TRect enlargedRect = rect + m_workBackupRect; + int dx = (enlargedRect.getLx() - 1) / denominator + 1; + int dy = (enlargedRect.getLy() - 1) / denominator + 1; + + if (m_workBackupRect.isEmpty()) { + enlargedRect.x0 -= dx; + enlargedRect.y0 -= dy; + enlargedRect.x1 += dx; + enlargedRect.y1 += dy; + + enlargedRect *= ras->getBounds(); + if (enlargedRect.isEmpty()) return; + + m_workRas->extract(enlargedRect)->copy(ras->extract(enlargedRect)); + m_backupRas->extract(enlargedRect)->copy(ras->extract(enlargedRect)); } else { - if (!m_workRas || m_workRas->getLx() > dim.lx || - m_workRas->getLy() > dim.ly) - m_workRas = TRaster32P(dim); - if (!m_backupRas || m_backupRas->getLx() > dim.lx || - m_backupRas->getLy() > dim.ly) - m_backupRas = TRasterCM32P(dim); - - m_painting.myPaint.strokeRect.empty(); - m_painting.lastRect.empty(); + if (enlargedRect.x0 < m_workBackupRect.x0) enlargedRect.x0 -= dx; + if (enlargedRect.y0 < m_workBackupRect.y0) enlargedRect.y0 -= dy; + if (enlargedRect.x1 > m_workBackupRect.x1) enlargedRect.x1 += dx; + if (enlargedRect.y1 > m_workBackupRect.y1) enlargedRect.y1 += dy; + + enlargedRect *= ras->getBounds(); + if (enlargedRect.isEmpty()) return; + + TRect lastRect = m_workBackupRect * ras->getBounds(); + QList rects = ToolUtils::splitRect(enlargedRect, lastRect); + for (int i = 0; i < rects.size(); i++) { + m_workRas->extract(rects[i])->copy(ras->extract(rects[i])); + m_backupRas->extract(rects[i])->copy(ras->extract(rects[i])); + } } + + m_workBackupRect = enlargedRect; } //------------------------------------------------------------------ @@ -2258,14 +1929,8 @@ bool ToonzRasterBrushTool::isPencilModeActive() { //------------------------------------------------------------------ void ToonzRasterBrushTool::onColorStyleChanged() { - // in case the style switched while drawing - if (m_painting.tileSaver) { - bool isValid = m_enabled && m_painting.active; - m_enabled = false; - if (isValid) { - finishRasterBrush(m_mousePos, 1); - } - } + m_inputmanager.finishTracks(); + m_enabled = false; TTool::Application *app = getApplication(); TMyPaintBrushStyle *mpbs = diff --git a/toonz/sources/tnztools/toonzrasterbrushtool.h b/toonz/sources/tnztools/toonzrasterbrushtool.h index 2b9875c..4f6ef26 100644 --- a/toonz/sources/tnztools/toonzrasterbrushtool.h +++ b/toonz/sources/tnztools/toonzrasterbrushtool.h @@ -3,15 +3,27 @@ #ifndef TOONZRASTERBRUSHTOOL_H #define TOONZRASTERBRUSHTOOL_H -#include "tgeometry.h" -#include "tproperty.h" -#include "trasterimage.h" -#include "ttoonzimage.h" -#include "tstroke.h" -#include "toonz/strokegenerator.h" - -#include "tools/tool.h" -#include "tools/cursors.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#ifndef NDEBUG +#include +#endif + +#include "bluredbrush.h" #include "mypainttoonzbrush.h" #include @@ -118,7 +130,9 @@ private: // Toonz Raster Brush Tool declaration //************************************************************************ -class ToonzRasterBrushTool final : public TTool, public RasterController { +class ToonzRasterBrushTool final : public TTool, + public RasterController, + public TInputHandler { Q_DECLARE_TR_FUNCTIONS(ToonzRasterBrushTool) void updateCurrentStyle(); @@ -142,6 +156,14 @@ public: void leftButtonUp(const TPointD &pos, const TMouseEvent &e) override; void mouseMove(const TPointD &pos, const TMouseEvent &e) override; + void inputMouseMove(const TPointD &position, + const TInputState &state) override; + void inputSetBusy(bool busy) override; + void inputPaintTrackPoint(const TTrackPoint &point, const TTrack &track, + bool firstTrack) override; + void inputInvalidateRect(const TRectD &bounds) override { invalidate(bounds); } + TTool *inputGetTool() override { return this; }; + void draw() override; void onEnter() override; @@ -162,7 +184,6 @@ public: void loadLastBrush(); - void finishRasterBrush(const TPointD &pos, double pressureVal); // return true if the pencil mode is active in the Brush / PaintBrush / Eraser // Tools. bool isPencilModeActive() override; @@ -172,35 +193,86 @@ public: bool askWrite(const TRect &rect) override; bool isMyPaintStyleSelected() { return m_isMyPaintStyleSelected; } +private: + enum MouseEventType { ME_DOWN, ME_DRAG, ME_UP, ME_MOVE }; + void handleMouseEvent(MouseEventType type, const TPointD &pos, + const TMouseEvent &e); + protected: - struct Stroke { - } m_stroke; + TInputManager m_inputmanager; +#ifndef NDEBUG + TSmartPointerT m_modifierTest; +#endif + TSmartPointerT m_modifierLine; + TSmartPointerT m_modifierTangents; + TSmartPointerT m_modifierAssistants; + TSmartPointerT m_modifierSegmentation; + + class MyPaintStroke: public TTrackToolHandler { + public: + MyPaintToonzBrush brush; + + inline MyPaintStroke( + const TRaster32P &ras, + RasterController &controller, + const mypaint::Brush &brush, + bool interpolation = false + ): + brush(ras, controller, brush, interpolation) + { } + }; + + class PencilStroke: public TTrackToolHandler { + public: + RasterStrokeGenerator brush; + + inline PencilStroke( const TRasterCM32P &raster, Tasks task, + ColorType colorType, int styleId, const TThickPoint &p, + bool selective, int selectedStyle, bool lockAlpha, + bool keepAntialias, bool isPaletteOrder = false + ): + brush(raster, task, colorType, styleId, p, selective, selectedStyle, lockAlpha, keepAntialias, isPaletteOrder) + { } + }; + + class BluredStroke: public TTrackToolHandler { + public: + BluredBrush brush; + + inline BluredStroke( const TRaster32P &ras, int size, + const QRadialGradient &gradient, bool doDynamicOpacity + ): + brush(ras, size, gradient, doDynamicOpacity) + { } + }; struct Painting { // initial painting input bool active = false; int styleId = 0; - bool smooth; + bool smooth = false; + // 作業中のFrameIdをクリック時に保存し、マウスリリース時(Undoの登録時)に別のフレームに 移動していたときの不具合を修正する。 + TFrameId frameId; // common variables TTileSetCM32 *tileSet = nullptr; TTileSaverCM32 *tileSaver = nullptr; - TRect lastRect; + TRect affectedRect; + SmoothStroke smoothStroke; struct Pencil { - RasterStrokeGenerator *brush = nullptr; + bool isActive = false; bool realPencil = false; } pencil; struct Blured { - BluredBrush *brush = nullptr; - std::vector points; + bool isActive = false; } blured; struct MyPaint { - MyPaintToonzBrush *brush = nullptr; - TRect strokeRect; + bool isActive = false; + mypaint::Brush baseBrush; TRect strokeSegmentRect; } myPaint; @@ -236,6 +308,7 @@ protected: TRasterCM32P m_backupRas; TRaster32P m_workRas; + TRect m_workBackupRect; BrushPresetManager m_presetsManager; //!< Manager for presets of this tool instance @@ -245,11 +318,6 @@ protected: //! substitution. m_firstTime, m_presetsLoaded; - /*--- -作業中のFrameIdをクリック時に保存し、マウスリリース時(Undoの登録時)に別のフレームに -移動していたときの不具合を修正する。---*/ - TFrameId m_workingFrameId; - ToonzRasterBrushToolNotifier *m_notifier; bool m_isMyPaintStyleSelected = false; QElapsedTimer m_brushTimer;