diff --git a/toonz/sources/include/tools/tooloptions.h b/toonz/sources/include/tools/tooloptions.h index 58e296c..f393606 100644 --- a/toonz/sources/include/tools/tooloptions.h +++ b/toonz/sources/include/tools/tooloptions.h @@ -458,6 +458,7 @@ class PaintbrushToolOptionsBox final : public ToolOptionsBox { ToolOptionCombo *m_colorMode; ToolOptionCheckbox *m_selectiveMode; + ToolOptionCheckbox *m_lockAlphaMode; public: PaintbrushToolOptionsBox(QWidget *parent, TTool *tool, diff --git a/toonz/sources/include/toonz/rasterstrokegenerator.h b/toonz/sources/include/toonz/rasterstrokegenerator.h index cda39fe..4b3f7ff 100644 --- a/toonz/sources/include/toonz/rasterstrokegenerator.h +++ b/toonz/sources/include/toonz/rasterstrokegenerator.h @@ -37,6 +37,7 @@ class DVAPI RasterStrokeGenerator { bool m_doAnArc; bool m_isPaletteOrder; // Used in the Draw Order option of Brush Tool, // use style order to define line stacking order + bool m_modifierLockAlpha; QSet m_aboveStyleIds; // Ricalcola i punti in un nuovo sistema di riferimento @@ -50,13 +51,14 @@ class DVAPI RasterStrokeGenerator { public: RasterStrokeGenerator(const TRasterCM32P &raster, Tasks task, ColorType colorType, int styleId, const TThickPoint &p, - bool selective, int selectedStyle, bool keepAntialias, - bool isPaletteOrder = false); + bool selective, int selectedStyle, bool lockAlpha, + bool keepAntialias, bool isPaletteOrder = false); ~RasterStrokeGenerator(); void setRaster(const TRasterCM32P &ras) { m_raster = ras; } void setStyle(int styleId) { m_styleId = styleId; } int getStyleId() const { return m_styleId; } bool isSelective() { return m_selective; } + bool isAlphaLocked() { return m_modifierLockAlpha; } bool isPaletteOrder() { return m_isPaletteOrder; } void setAboveStyleIds(QSet &ids) { m_aboveStyleIds = ids; } diff --git a/toonz/sources/tnztools/bluredbrush.cpp b/toonz/sources/tnztools/bluredbrush.cpp index fdc01a0..9530079 100644 --- a/toonz/sources/tnztools/bluredbrush.cpp +++ b/toonz/sources/tnztools/bluredbrush.cpp @@ -27,7 +27,8 @@ QImage rasterToQImage(const TRasterP &ras, bool premultiplied = false) { //---------------------------------------------------------------------------------- // drawOrderMode : 0=OverAll, 1=UnderAll, 2=PaletteOrder void putOnRasterCM(const TRasterCM32P &out, const TRaster32P &in, int styleId, - int drawOrderMode, const QSet &aboveStyleIds) { + int drawOrderMode, bool lockAlpha, + const QSet &aboveStyleIds) { if (!out.getPointer() || !in.getPointer()) return; assert(out->getSize() == in->getSize()); int x, y; @@ -43,6 +44,12 @@ void putOnRasterCM(const TRasterCM32P &out, const TRaster32P &in, int styleId, TPixel32 *inPix = &in->pixels(y)[x]; if (inPix->m == 0) continue; TPixelCM32 *outPix = &out->pixels(y)[x]; + if (lockAlpha && !outPix->isPureInk() && outPix->getPaint() == 0 && + outPix->getTone() == 255) { + *outPix = TPixelCM32(outPix->getInk(), outPix->getPaint(), + outPix->getTone()); + continue; + } bool sameStyleId = styleId == outPix->getInk(); // line with the same style : multiply tones // line with different style : pick darker tone @@ -66,6 +73,12 @@ void putOnRasterCM(const TRasterCM32P &out, const TRaster32P &in, int styleId, TPixel32 *inPix = &in->pixels(y)[x]; if (inPix->m == 0) continue; TPixelCM32 *outPix = &out->pixels(y)[x]; + if (lockAlpha && !outPix->isPureInk() && outPix->getPaint() == 0 && + outPix->getTone() == 255) { + *outPix = TPixelCM32(outPix->getInk(), outPix->getPaint(), + outPix->getTone()); + continue; + } bool sameStyleId = styleId == outPix->getInk(); // line with the same style : multiply tones // line with different style : pick darker tone @@ -83,6 +96,12 @@ void putOnRasterCM(const TRasterCM32P &out, const TRaster32P &in, int styleId, TPixel32 *inPix = &in->pixels(y)[x]; if (inPix->m == 0) continue; TPixelCM32 *outPix = &out->pixels(y)[x]; + if (lockAlpha && !outPix->isPureInk() && outPix->getPaint() == 0 && + outPix->getTone() == 255) { + *outPix = TPixelCM32(outPix->getInk(), outPix->getPaint(), + outPix->getTone()); + continue; + } bool sameStyleId = styleId == outPix->getInk(); // line with the same style : multiply tones // line with different style : pick darker tone @@ -365,7 +384,7 @@ void BluredBrush::eraseDrawing(const TRasterP ras, const TRasterP rasBackup, void BluredBrush::updateDrawing(const TRasterCM32P rasCM, const TRasterCM32P rasBackupCM, const TRect &bbox, int styleId, - int drawOrderMode) const { + int drawOrderMode, bool lockAlpha) const { if (!rasCM) return; TRect rasRect = rasCM->getBounds(); @@ -374,7 +393,7 @@ void BluredBrush::updateDrawing(const TRasterCM32P rasCM, rasCM->copy(rasBackupCM->extract(targetRect), targetRect.getP00()); putOnRasterCM(rasCM->extract(targetRect), m_ras->extract(targetRect), styleId, - drawOrderMode, m_aboveStyleIds); + drawOrderMode, lockAlpha, m_aboveStyleIds); } //---------------------------------------------------------------------------------- diff --git a/toonz/sources/tnztools/bluredbrush.h b/toonz/sources/tnztools/bluredbrush.h index e1468a4..3f7a32c 100644 --- a/toonz/sources/tnztools/bluredbrush.h +++ b/toonz/sources/tnztools/bluredbrush.h @@ -40,7 +40,8 @@ public: TRect getBoundFromPoints(const std::vector &points) const; // colormapped void updateDrawing(const TRasterCM32P rasCM, const TRasterCM32P rasBackupCM, - const TRect &bbox, int styleId, int drawOrderMode) const; + const TRect &bbox, int styleId, int drawOrderMode, + bool lockAlpha) const; void eraseDrawing(const TRasterCM32P rasCM, const TRasterCM32P rasBackupCM, const TRect &bbox, bool selective, int selectedStyleId, const std::wstring &mode) const; diff --git a/toonz/sources/tnztools/fingertool.cpp b/toonz/sources/tnztools/fingertool.cpp index d4f1d05..09f6ef5 100644 --- a/toonz/sources/tnztools/fingertool.cpp +++ b/toonz/sources/tnztools/fingertool.cpp @@ -75,7 +75,7 @@ public: TToonzImageP image = m_level->getFrame(m_frameId, true); TRasterCM32P ras = image->getRaster(); RasterStrokeGenerator m_rasterTrack(ras, FINGER, INK, m_styleId, - m_points[0], m_invert, 0, false); + m_points[0], m_invert, 0, false, false); m_rasterTrack.setPointsSequence(m_points); m_rasterTrack.generateStroke(true); image->setSavebox(image->getSavebox() + @@ -409,7 +409,7 @@ void FingerTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) { m_rasterTrack = new RasterStrokeGenerator( ras, FINGER, INK, styleId, TThickPoint(pos + convert(ras->getCenter()), thickness), - m_invert.getValue(), 0, false); + m_invert.getValue(), 0, false, false); /*-- 作業中Fidを現在のFIDにする --*/ m_workingFrameId = getFrameId(); diff --git a/toonz/sources/tnztools/fullcolorbrushtool.cpp b/toonz/sources/tnztools/fullcolorbrushtool.cpp index 0c12dc5..9f1bf7b 100644 --- a/toonz/sources/tnztools/fullcolorbrushtool.cpp +++ b/toonz/sources/tnztools/fullcolorbrushtool.cpp @@ -121,7 +121,7 @@ FullColorBrushTool::FullColorBrushTool(std::string name) , m_modifierSize("ModifierSize", -3, 3, 0, true) , m_modifierOpacity("ModifierOpacity", 0, 100, 100, true) , m_modifierEraser("ModifierEraser", false) - , m_modifierLockAlpha("ModifierLockAlpha", false) + , m_modifierLockAlpha("Lock Alpha", false) , m_preset("Preset:") , m_minCursorThick(0) , m_maxCursorThick(0) @@ -890,6 +890,10 @@ void FullColorBrushTool::applyClassicToonzBrushSettings( MYPAINT_BRUSH_INPUT_PRESSURE, 1, 1.0, maxOpacity - minOpacity); } + + if (m_modifierLockAlpha.getValue()) { + mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_LOCK_ALPHA, 1.0); + } } void FullColorBrushTool::applyToonzBrushSettings(mypaint::Brush &mypaintBrush) { diff --git a/toonz/sources/tnztools/geometrictool.cpp b/toonz/sources/tnztools/geometrictool.cpp index a99b324..f878ee0 100644 --- a/toonz/sources/tnztools/geometrictool.cpp +++ b/toonz/sources/tnztools/geometrictool.cpp @@ -181,7 +181,7 @@ static TRect drawBluredBrush(const TToonzImageP &ti, TStroke *stroke, int thick, TRect chunkBox = brush.getBoundFromPoints(points); brush.addArc(points[0], points[1], points[2], 1, 1); brush.updateDrawing(ti->getRaster(), backupRas, chunkBox, styleId, - selective); + selective, false); } delete s; diff --git a/toonz/sources/tnztools/mypainttoonzbrush.cpp b/toonz/sources/tnztools/mypainttoonzbrush.cpp index c3670dc..deb9b04 100644 --- a/toonz/sources/tnztools/mypainttoonzbrush.cpp +++ b/toonz/sources/tnztools/mypainttoonzbrush.cpp @@ -9,7 +9,8 @@ #include namespace { -void putOnRasterCM(const TRasterCM32P &out, const TRaster32P &in, int styleId) { +void putOnRasterCM(const TRasterCM32P &out, const TRaster32P &in, int styleId, + bool lockAlpha) { if (!out.getPointer() || !in.getPointer()) return; assert(out->getSize() == in->getSize()); int x, y; @@ -24,7 +25,13 @@ void putOnRasterCM(const TRasterCM32P &out, const TRaster32P &in, int styleId) { TPixel32 *inPix = &in->pixels(y)[x]; if (inPix->m == 0) continue; TPixelCM32 *outPix = &out->pixels(y)[x]; - bool sameStyleId = styleId == outPix->getInk(); + if (lockAlpha && !outPix->isPureInk() && outPix->getPaint() == 0 && + outPix->getTone() == 255) { + *outPix = + TPixelCM32(outPix->getInk(), outPix->getPaint(), outPix->getTone()); + continue; + } + bool sameStyleId = styleId == outPix->getInk(); // line with the same style : multiply tones // line with different style : pick darker tone int tone = sameStyleId ? outPix->getTone() * (255 - inPix->m) / 255 @@ -196,7 +203,8 @@ void MyPaintToonzBrush::strokeTo(const TPointD &point, double pressure, void MyPaintToonzBrush::updateDrawing(const TRasterCM32P rasCM, const TRasterCM32P rasBackupCM, - const TRect &bbox, int styleId) const { + const TRect &bbox, int styleId, + bool lockAlpha) const { if (!rasCM) return; TRect rasRect = rasCM->getBounds(); @@ -204,6 +212,6 @@ void MyPaintToonzBrush::updateDrawing(const TRasterCM32P rasCM, if (targetRect.isEmpty()) return; rasCM->copy(rasBackupCM->extract(targetRect), targetRect.getP00()); - putOnRasterCM(rasCM->extract(targetRect), m_ras->extract(targetRect), - styleId); + putOnRasterCM(rasCM->extract(targetRect), m_ras->extract(targetRect), styleId, + lockAlpha); } \ No newline at end of file diff --git a/toonz/sources/tnztools/mypainttoonzbrush.h b/toonz/sources/tnztools/mypainttoonzbrush.h index 352afa5..f26aa60 100644 --- a/toonz/sources/tnztools/mypainttoonzbrush.h +++ b/toonz/sources/tnztools/mypainttoonzbrush.h @@ -130,7 +130,7 @@ public: // colormapped void updateDrawing(const TRasterCM32P rasCM, const TRasterCM32P rasBackupCM, - const TRect &bbox, int styleId) const; + const TRect &bbox, int styleId, bool lockAlpha) const; }; #endif // T_BLUREDBRUSH diff --git a/toonz/sources/tnztools/paintbrushtool.cpp b/toonz/sources/tnztools/paintbrushtool.cpp index de316b3..e53b245 100644 --- a/toonz/sources/tnztools/paintbrushtool.cpp +++ b/toonz/sources/tnztools/paintbrushtool.cpp @@ -47,6 +47,7 @@ using namespace ToolUtils; TEnv::StringVar PaintBrushColorType("InknpaintPaintBrushColorType", "Areas"); TEnv::IntVar PaintBrushSelective("InknpaintPaintBrushSelective", 0); TEnv::DoubleVar PaintBrushSize("InknpaintPaintBrushSize", 10); +TEnv::IntVar PaintBrushModifierLockAlpha("PaintBrushModifierLockAlpha", 0); //----------------------------------------------------------------------------- @@ -61,22 +62,25 @@ class BrushUndo final : public TRasterUndo { int m_styleId; bool m_selective; ColorType m_colorType; + bool m_modifierLockAlpha; public: BrushUndo(TTileSetCM32 *tileSet, const std::vector &points, ColorType colorType, int styleId, bool selective, - TXshSimpleLevel *level, const TFrameId &frameId) + TXshSimpleLevel *level, const TFrameId &frameId, bool lockAlpha) : TRasterUndo(tileSet, level, frameId, false, false, 0) , m_points(points) , m_styleId(styleId) , m_selective(selective) - , m_colorType(colorType) {} + , m_colorType(colorType) + , m_modifierLockAlpha(lockAlpha) {} void redo() const override { TToonzImageP image = m_level->getFrame(m_frameId, true); TRasterCM32P ras = image->getRaster(); RasterStrokeGenerator m_rasterTrack(ras, PAINTBRUSH, m_colorType, m_styleId, - m_points[0], m_selective, 0, false); + m_points[0], m_selective, 0, + m_modifierLockAlpha, false); m_rasterTrack.setPointsSequence(m_points); m_rasterTrack.generateStroke(true); image->setSavebox(image->getSavebox() + @@ -266,6 +270,8 @@ class PaintBrushTool final : public TTool { 移動している場合に備える --*/ TFrameId m_workingFrameId; + TBoolProperty m_modifierLockAlpha; + public: PaintBrushTool(); @@ -324,7 +330,8 @@ PaintBrushTool::PaintBrushTool() , m_colorType("Mode:") // W_ToolOptions_InkOrPaint , m_onlyEmptyAreas("Selective", false) // W_ToolOptions_Selective , m_firstTime(true) - , m_workingFrameId(TFrameId()) { + , m_workingFrameId(TFrameId()) + , m_modifierLockAlpha("Lock Alpha", false) { m_toolSize.setNonLinearSlider(); m_colorType.addValue(LINES); @@ -336,9 +343,11 @@ PaintBrushTool::PaintBrushTool() m_prop.bind(m_toolSize); m_prop.bind(m_colorType); m_prop.bind(m_onlyEmptyAreas); + m_prop.bind(m_modifierLockAlpha); m_onlyEmptyAreas.setId("Selective"); m_colorType.setId("Mode"); + m_modifierLockAlpha.setId("LockAlpha"); } //----------------------------------------------------------------------------- @@ -352,6 +361,7 @@ void PaintBrushTool::updateTranslation() { m_colorType.setItemUIName(ALL, tr("Lines & Areas")); m_onlyEmptyAreas.setQStringName(tr("Selective", NULL)); + m_modifierLockAlpha.setQStringName(tr("Lock Alpha")); } //------------------------------------------------------------------------------------------------------- @@ -435,6 +445,8 @@ bool PaintBrushTool::onPropertyChanged(std::string propertyName) { // Selective else if (propertyName == m_onlyEmptyAreas.getName()) { PaintBrushSelective = (int)(m_onlyEmptyAreas.getValue()); + if (m_onlyEmptyAreas.getValue() && m_modifierLockAlpha.getValue()) + m_modifierLockAlpha.setValue(false); } // Areas, Lines etc. @@ -444,6 +456,12 @@ bool PaintBrushTool::onPropertyChanged(std::string propertyName) { TTool::getApplication()->getCurrentTool()->notifyToolChanged(); } + // Lock Alpha + else if (propertyName == m_modifierLockAlpha.getName()) { + PaintBrushModifierLockAlpha = (int)(m_modifierLockAlpha.getValue()); + if (m_modifierLockAlpha.getValue() && m_onlyEmptyAreas.getValue()) + m_onlyEmptyAreas.setValue(false); + } return true; } @@ -467,7 +485,8 @@ void PaintBrushTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) { m_rasterTrack = new RasterStrokeGenerator( ras, PAINTBRUSH, m_colorTypeBrush, styleId, TThickPoint(m_mousePos + convert(ras->getCenter()), thickness), - m_onlyEmptyAreas.getValue(), 0, false); + m_onlyEmptyAreas.getValue(), 0, m_modifierLockAlpha.getValue(), + false); /*-- 現在のFidを記憶 --*/ m_workingFrameId = getFrameId(); m_tileSaver->save(m_rasterTrack->getLastRect()); @@ -522,6 +541,7 @@ void PaintBrushTool::onEnter() { m_onlyEmptyAreas.setValue(PaintBrushSelective ? 1 : 0); m_colorType.setValue(::to_wstring(PaintBrushColorType.getValue())); m_toolSize.setValue(PaintBrushSize); + m_modifierLockAlpha.setValue(PaintBrushModifierLockAlpha ? 1 : 0); m_firstTime = false; } double x = m_toolSize.getValue(); @@ -581,7 +601,8 @@ void PaintBrushTool::finishBrush() { TUndoManager::manager()->add(new BrushUndo( m_tileSaver->getTileSet(), m_rasterTrack->getPointsSequence(), m_colorTypeBrush, m_rasterTrack->getStyleId(), - m_rasterTrack->isSelective(), simLevel.getPointer(), frameId)); + m_rasterTrack->isSelective(), simLevel.getPointer(), frameId, + m_rasterTrack->isAlphaLocked())); ToolUtils::updateSaveBox(); /*--- FIdを指定して、描画中にフレームが変わっても、 diff --git a/toonz/sources/tnztools/rastererasertool.cpp b/toonz/sources/tnztools/rastererasertool.cpp index 0d98c65..8ffaec4 100644 --- a/toonz/sources/tnztools/rastererasertool.cpp +++ b/toonz/sources/tnztools/rastererasertool.cpp @@ -178,7 +178,7 @@ public: TToonzImageP image = m_level->getFrame(m_frameId, true); TRasterCM32P ras = image->getRaster(); RasterStrokeGenerator m_rasterTrack(ras, ERASE, m_colorType, 0, m_points[0], - m_selective, m_colorSelected, + m_selective, m_colorSelected, false, !m_isPencil); m_rasterTrack.setPointsSequence(m_points); m_rasterTrack.generateStroke(m_isPencil); @@ -939,7 +939,7 @@ void EraserTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) { if (m_colorType.getValue() == ALL) m_colorTypeEraser = INKNPAINT; m_normalEraser = new RasterStrokeGenerator( raster, ERASE, m_colorTypeEraser, 0, intPos, - m_currentStyle.getValue(), currentStyle, + m_currentStyle.getValue(), currentStyle, false, !(m_pencil.getValue() || m_colorType.getValue() == AREAS)); m_tileSaver->save(m_normalEraser->getLastRect()); m_normalEraser->generateLastPieceOfStroke( diff --git a/toonz/sources/tnztools/tooloptions.cpp b/toonz/sources/tnztools/tooloptions.cpp index 63214ed..d4b05d2 100644 --- a/toonz/sources/tnztools/tooloptions.cpp +++ b/toonz/sources/tnztools/tooloptions.cpp @@ -1486,9 +1486,13 @@ PaintbrushToolOptionsBox::PaintbrushToolOptionsBox(QWidget *parent, TTool *tool, m_colorMode = dynamic_cast(m_controls.value("Mode:")); m_selectiveMode = dynamic_cast(m_controls.value("Selective")); + m_lockAlphaMode = + dynamic_cast(m_controls.value("Lock Alpha")); - if (m_colorMode->getProperty()->getValue() == L"Lines") + if (m_colorMode->getProperty()->getValue() == L"Lines") { m_selectiveMode->setVisible(false); + m_lockAlphaMode->setVisible(false); + } bool ret = connect(m_colorMode, SIGNAL(currentIndexChanged(int)), this, SLOT(onColorModeChanged(int))); @@ -1509,6 +1513,7 @@ void PaintbrushToolOptionsBox::onColorModeChanged(int index) { const TEnumProperty::Range &range = m_colorMode->getProperty()->getRange(); bool enabled = range[index] != L"Lines"; m_selectiveMode->setVisible(enabled); + m_lockAlphaMode->setVisible(enabled); } //============================================================================= @@ -1779,16 +1784,18 @@ void BrushToolOptionsBox::filterControls() { for (QMap::iterator it = m_labels.begin(); it != m_labels.end(); it++) { bool isModifier = (it.key().substr(0, 8) == "Modifier"); - bool isCommon = (it.key() == "Pressure" || it.key() == "Preset:"); - bool visible = isCommon || (isModifier == showModifiers); + bool isCommon = (it.key() == "Lock Alpha" || it.key() == "Pressure" || + it.key() == "Preset:"); + bool visible = isCommon || (isModifier == showModifiers); it.value()->setVisible(visible); } for (QMap::iterator it = m_controls.begin(); it != m_controls.end(); it++) { bool isModifier = (it.key().substr(0, 8) == "Modifier"); - bool isCommon = (it.key() == "Pressure" || it.key() == "Preset:"); - bool visible = isCommon || (isModifier == showModifiers); + bool isCommon = (it.key() == "Lock Alpha" || it.key() == "Pressure" || + it.key() == "Preset:"); + bool visible = isCommon || (isModifier == showModifiers); if (QWidget *widget = dynamic_cast(it.value())) widget->setVisible(visible); } diff --git a/toonz/sources/tnztools/toonzrasterbrushtool.cpp b/toonz/sources/tnztools/toonzrasterbrushtool.cpp index 36a77b6..db1db72 100644 --- a/toonz/sources/tnztools/toonzrasterbrushtool.cpp +++ b/toonz/sources/tnztools/toonzrasterbrushtool.cpp @@ -56,6 +56,7 @@ TEnv::IntVar BrushPressureSensitivity("InknpaintBrushPressureSensitivity", 1); TEnv::DoubleVar RasterBrushHardness("RasterBrushHardness", 100); TEnv::DoubleVar RasterBrushModifierSize("RasterBrushModifierSize", 0); TEnv::StringVar RasterBrushPreset("RasterBrushPreset", ""); +TEnv::IntVar BrushLockAlpha("InknpaintBrushLockAlpha", 0); //------------------------------------------------------------------- #define CUSTOM_WSTR L"" @@ -436,26 +437,28 @@ class RasterBrushUndo final : public TRasterUndo { bool m_selective; bool m_isPaletteOrder; bool m_isPencil; + bool m_modifierLockAlpha; public: RasterBrushUndo(TTileSetCM32 *tileSet, const std::vector &points, int styleId, bool selective, TXshSimpleLevel *level, const TFrameId &frameId, bool isPencil, bool isFrameCreated, - bool isLevelCreated, bool isPaletteOrder) + bool isLevelCreated, bool isPaletteOrder, bool lockAlpha) : TRasterUndo(tileSet, level, frameId, isFrameCreated, isLevelCreated, 0) , m_points(points) , m_styleId(styleId) , m_selective(selective) , m_isPencil(isPencil) - , m_isPaletteOrder(isPaletteOrder) {} + , m_isPaletteOrder(isPaletteOrder) + , m_modifierLockAlpha(lockAlpha) {} void redo() const override { insertLevelAndFrameIfNeeded(); TToonzImageP image = getImage(); TRasterCM32P ras = image->getRaster(); - RasterStrokeGenerator m_rasterTrack(ras, BRUSH, NONE, m_styleId, - m_points[0], m_selective, 0, - !m_isPencil, m_isPaletteOrder); + RasterStrokeGenerator m_rasterTrack( + ras, BRUSH, NONE, m_styleId, m_points[0], m_selective, 0, + m_modifierLockAlpha, !m_isPencil, m_isPaletteOrder); if (m_isPaletteOrder) { QSet aboveStyleIds; getAboveStyleIdSet(m_styleId, image->getPalette(), aboveStyleIds); @@ -485,19 +488,22 @@ class RasterBluredBrushUndo final : public TRasterUndo { DrawOrder m_drawOrder; int m_maxThick; double m_hardness; + bool m_modifierLockAlpha; public: RasterBluredBrushUndo(TTileSetCM32 *tileSet, const std::vector &points, int styleId, - DrawOrder drawOrder, TXshSimpleLevel *level, - const TFrameId &frameId, int maxThick, double hardness, - bool isFrameCreated, bool isLevelCreated) + DrawOrder drawOrder, bool lockAlpha, + TXshSimpleLevel *level, const TFrameId &frameId, + int maxThick, double hardness, bool isFrameCreated, + bool isLevelCreated) : TRasterUndo(tileSet, level, frameId, isFrameCreated, isLevelCreated, 0) , m_points(points) , m_styleId(styleId) , m_drawOrder(drawOrder) , m_maxThick(maxThick) - , m_hardness(hardness) {} + , m_hardness(hardness) + , m_modifierLockAlpha(lockAlpha) {} void redo() const override { if (m_points.size() == 0) return; @@ -520,7 +526,8 @@ public: points.push_back(m_points[0]); TRect bbox = brush.getBoundFromPoints(points); brush.addPoint(m_points[0], 1); - brush.updateDrawing(ras, ras, bbox, m_styleId, (int)m_drawOrder); + brush.updateDrawing(ras, ras, bbox, m_styleId, (int)m_drawOrder, + m_modifierLockAlpha); if (m_points.size() > 1) { points.clear(); points.push_back(m_points[0]); @@ -528,7 +535,8 @@ public: bbox = brush.getBoundFromPoints(points); brush.addArc(m_points[0], (m_points[1] + m_points[0]) * 0.5, m_points[1], 1, 1); - brush.updateDrawing(ras, backupRas, bbox, m_styleId, (int)m_drawOrder); + brush.updateDrawing(ras, backupRas, bbox, m_styleId, (int)m_drawOrder, + m_modifierLockAlpha); int i; for (i = 1; i + 2 < (int)m_points.size(); i = i + 2) { points.clear(); @@ -537,7 +545,8 @@ public: points.push_back(m_points[i + 2]); bbox = brush.getBoundFromPoints(points); brush.addArc(m_points[i], m_points[i + 1], m_points[i + 2], 1, 1); - brush.updateDrawing(ras, backupRas, bbox, m_styleId, (int)m_drawOrder); + brush.updateDrawing(ras, backupRas, bbox, m_styleId, (int)m_drawOrder, + m_modifierLockAlpha); } } ToolUtils::updateSaveBox(); @@ -864,7 +873,8 @@ ToonzRasterBrushTool::ToonzRasterBrushTool(std::string name, int targetType) , m_presetsLoaded(false) , m_targetType(targetType) , m_workingFrameId(TFrameId()) - , m_notifier(0) { + , m_notifier(0) + , m_modifierLockAlpha("Lock Alpha", false) { bind(targetType); m_rasThickness.setNonLinearSlider(); @@ -874,6 +884,7 @@ ToonzRasterBrushTool::ToonzRasterBrushTool(std::string name, int targetType) m_prop[0].bind(m_smooth); m_prop[0].bind(m_drawOrder); m_prop[0].bind(m_modifierSize); + m_prop[0].bind(m_modifierLockAlpha); m_prop[0].bind(m_pencil); m_pencil.setId("PencilMode"); @@ -888,6 +899,7 @@ ToonzRasterBrushTool::ToonzRasterBrushTool(std::string name, int targetType) m_preset.setId("BrushPreset"); m_preset.addValue(CUSTOM_WSTR); m_pressure.setId("PressureSensitivity"); + m_modifierLockAlpha.setId("LockAlpha"); } //------------------------------------------------------------------------------------------------------- @@ -1081,6 +1093,7 @@ void ToonzRasterBrushTool::updateTranslation() { m_preset.setItemUIName(CUSTOM_WSTR, tr("")); m_pencil.setQStringName(tr("Pencil")); m_pressure.setQStringName(tr("Pressure")); + m_modifierLockAlpha.setQStringName(tr("Lock Alpha")); } //--------------------------------------------------------------------------------------------------- @@ -1322,7 +1335,7 @@ void ToonzRasterBrushTool::leftButtonDown(const TPointD &pos, if (!updateRect.isEmpty()) { // ras->extract(updateRect)->copy(m_workRas->extract(updateRect)); m_toonz_brush->updateDrawing(ri->getRaster(), m_backupRas, m_strokeRect, - m_styleId); + m_styleId, m_modifierLockAlpha.getValue()); } m_lastRect = m_strokeRect; @@ -1341,7 +1354,8 @@ void ToonzRasterBrushTool::leftButtonDown(const TPointD &pos, thickness); m_rasterTrack = new RasterStrokeGenerator( ras, BRUSH, NONE, m_styleId, thickPoint, drawOrder != OverAll, 0, - !m_pencil.getValue(), drawOrder == PaletteOrder); + m_modifierLockAlpha.getValue(), !m_pencil.getValue(), + drawOrder == PaletteOrder); if (drawOrder == PaletteOrder) m_rasterTrack->setAboveStyleIds(aboveStyleIds); @@ -1371,7 +1385,8 @@ void ToonzRasterBrushTool::leftButtonDown(const TPointD &pos, m_tileSaver->save(m_strokeRect); m_bluredBrush->addPoint(point, 1); m_bluredBrush->updateDrawing(ri->getRaster(), m_backupRas, m_strokeRect, - m_styleId, drawOrder); + m_styleId, drawOrder, + m_modifierLockAlpha.getValue()); m_lastRect = m_strokeRect; std::vector pts; @@ -1424,7 +1439,7 @@ void ToonzRasterBrushTool::leftButtonDrag(const TPointD &pos, if (!updateRect.isEmpty()) { // ras->extract(updateRect)->copy(m_workRaster->extract(updateRect)); m_toonz_brush->updateDrawing(ras, m_backupRas, m_strokeSegmentRect, - m_styleId); + m_styleId, m_modifierLockAlpha.getValue()); } m_lastRect = m_strokeRect; @@ -1511,7 +1526,8 @@ void ToonzRasterBrushTool::leftButtonDrag(const TPointD &pos, invalidateRect += ToolUtils::getBounds(points, maxThickness) - rasCenter; m_bluredBrush->updateDrawing(ti->getRaster(), m_backupRas, bbox, - m_styleId, m_drawOrder.getIndex()); + m_styleId, m_drawOrder.getIndex(), + m_modifierLockAlpha.getValue()); m_strokeRect += bbox; } } @@ -1578,7 +1594,7 @@ void ToonzRasterBrushTool::finishRasterBrush(const TPointD &pos, if (!updateRect.isEmpty()) { // ras->extract(updateRect)->copy(m_workRaster->extract(updateRect)); m_toonz_brush->updateDrawing(ras, m_backupRas, m_strokeSegmentRect, - m_styleId); + m_styleId, m_modifierLockAlpha.getValue()); } TPointD thickOffset(m_maxCursorThick * 0.5, m_maxCursorThick * 0.5); // TODO @@ -1651,7 +1667,8 @@ void ToonzRasterBrushTool::finishRasterBrush(const TPointD &pos, m_tileSet, m_rasterTrack->getPointsSequence(), m_rasterTrack->getStyleId(), m_rasterTrack->isSelective(), simLevel.getPointer(), frameId, m_pencil.getValue(), m_isFrameCreated, - m_isLevelCreated, m_rasterTrack->isPaletteOrder())); + m_isLevelCreated, m_rasterTrack->isPaletteOrder(), + m_rasterTrack->isAlphaLocked())); } delete m_rasterTrack; m_rasterTrack = 0; @@ -1710,7 +1727,8 @@ void ToonzRasterBrushTool::finishRasterBrush(const TPointD &pos, ToolUtils::getBounds(points, maxThickness) - rasCenter; m_bluredBrush->updateDrawing(ti->getRaster(), m_backupRas, bbox, - m_styleId, m_drawOrder.getIndex()); + m_styleId, m_drawOrder.getIndex(), + m_modifierLockAlpha.getValue()); m_strokeRect += bbox; } TThickPoint point = pts.back(); @@ -1725,7 +1743,8 @@ void ToonzRasterBrushTool::finishRasterBrush(const TPointD &pos, m_tileSaver->save(bbox); m_bluredBrush->addArc(points[0], points[1], points[2], 1, 1); m_bluredBrush->updateDrawing(ti->getRaster(), m_backupRas, bbox, - m_styleId, m_drawOrder.getIndex()); + m_styleId, m_drawOrder.getIndex(), + m_modifierLockAlpha.getValue()); invalidateRect += ToolUtils::getBounds(points, maxThickness) - rasCenter; @@ -1741,8 +1760,9 @@ void ToonzRasterBrushTool::finishRasterBrush(const TPointD &pos, if (m_tileSet->getTileCount() > 0) { TUndoManager::manager()->add(new RasterBluredBrushUndo( m_tileSet, m_points, m_styleId, (DrawOrder)m_drawOrder.getIndex(), - simLevel.getPointer(), frameId, m_rasThickness.getValue().second, - m_hardness.getValue() * 0.01, m_isFrameCreated, m_isLevelCreated)); + m_modifierLockAlpha.getValue(), simLevel.getPointer(), frameId, + m_rasThickness.getValue().second, m_hardness.getValue() * 0.01, + m_isFrameCreated, m_isLevelCreated)); } } delete m_tileSaver; @@ -1992,6 +2012,7 @@ bool ToonzRasterBrushTool::onPropertyChanged(std::string propertyName) { BrushPressureSensitivity = m_pressure.getValue(); RasterBrushHardness = m_hardness.getValue(); RasterBrushModifierSize = m_modifierSize.getValue(); + BrushLockAlpha = m_modifierLockAlpha.getValue(); // Recalculate/reset based on changed settings if (propertyName == m_rasThickness.getName()) { @@ -2062,6 +2083,7 @@ void ToonzRasterBrushTool::loadPreset() { m_pencil.setValue(preset.m_pencil); m_pressure.setValue(preset.m_pressure); m_modifierSize.setValue(preset.m_modifierSize); + m_modifierLockAlpha.setValue(preset.m_modifierLockAlpha); // Recalculate based on updated presets m_minThick = m_rasThickness.getValue().first; @@ -2083,12 +2105,13 @@ void ToonzRasterBrushTool::addPreset(QString name) { preset.m_min = m_rasThickness.getValue().first; preset.m_max = m_rasThickness.getValue().second; - preset.m_smooth = m_smooth.getValue(); - preset.m_hardness = m_hardness.getValue(); - preset.m_drawOrder = m_drawOrder.getIndex(); - preset.m_pencil = m_pencil.getValue(); - preset.m_pressure = m_pressure.getValue(); - preset.m_modifierSize = m_modifierSize.getValue(); + preset.m_smooth = m_smooth.getValue(); + preset.m_hardness = m_hardness.getValue(); + preset.m_drawOrder = m_drawOrder.getIndex(); + preset.m_pencil = m_pencil.getValue(); + preset.m_pressure = m_pressure.getValue(); + preset.m_modifierSize = m_modifierSize.getValue(); + preset.m_modifierLockAlpha = m_modifierLockAlpha.getValue(); // Pass the preset to the manager m_presetsManager.addPreset(preset); @@ -2126,6 +2149,7 @@ void ToonzRasterBrushTool::loadLastBrush() { m_pressure.setValue(BrushPressureSensitivity ? 1 : 0); m_smooth.setValue(BrushSmooth); m_modifierSize.setValue(RasterBrushModifierSize); + m_modifierLockAlpha.setValue(BrushLockAlpha ? 1 : 0); // Recalculate based on prior values m_minThick = m_rasThickness.getValue().first; diff --git a/toonz/sources/tnztools/toonzrasterbrushtool.h b/toonz/sources/tnztools/toonzrasterbrushtool.h index 2dfab81..eeaf0b2 100644 --- a/toonz/sources/tnztools/toonzrasterbrushtool.h +++ b/toonz/sources/tnztools/toonzrasterbrushtool.h @@ -182,6 +182,7 @@ protected: TBoolProperty m_pencil; TBoolProperty m_pressure; TDoubleProperty m_modifierSize; + TBoolProperty m_modifierLockAlpha; RasterStrokeGenerator *m_rasterTrack; TTileSetCM32 *m_tileSet; diff --git a/toonz/sources/toonzlib/rasterstrokegenerator.cpp b/toonz/sources/toonzlib/rasterstrokegenerator.cpp index fda0821..393d5df 100644 --- a/toonz/sources/toonzlib/rasterstrokegenerator.cpp +++ b/toonz/sources/toonzlib/rasterstrokegenerator.cpp @@ -9,7 +9,7 @@ RasterStrokeGenerator::RasterStrokeGenerator(const TRasterCM32P &raster, Tasks task, ColorType colorType, int styleId, const TThickPoint &p, bool selective, int selectedStyle, - bool keepAntialias, + bool lockAlpha, bool keepAntialias, bool isPaletteOrder) : m_raster(raster) , m_boxOfRaster(TRect(raster->getSize())) @@ -21,7 +21,8 @@ RasterStrokeGenerator::RasterStrokeGenerator(const TRasterCM32P &raster, , m_selectedStyle(selectedStyle) , m_keepAntiAlias(keepAntialias) , m_doAnArc(false) - , m_isPaletteOrder(isPaletteOrder) { + , m_isPaletteOrder(isPaletteOrder) + , m_modifierLockAlpha(lockAlpha) { TThickPoint pp = p; m_points.push_back(pp); if (task == ERASE) m_styleId = m_eraseStyle; @@ -188,10 +189,15 @@ void RasterStrokeGenerator::placeOver(const TRasterCM32P &out, if (m_task == BRUSH) { int inTone = inPix->getTone(); int outTone = outPix->getTone(); - if (inPix->isPureInk() && !m_selective) { + if (inPix->isPureInk() && !m_selective && !m_modifierLockAlpha) { *outPix = TPixelCM32(inPix->getInk(), outPix->getPaint(), inTone); continue; } + if (m_modifierLockAlpha && !outPix->isPureInk() && + outPix->getPaint() == 0 && outPix->getTone() == 255) { + *outPix = TPixelCM32(outPix->getInk(), outPix->getPaint(), outTone); + continue; + } if (outPix->isPureInk() && m_selective) { if (!m_isPaletteOrder || m_aboveStyleIds.contains(outPix->getInk())) { *outPix = TPixelCM32(outPix->getInk(), outPix->getPaint(), outTone); @@ -243,8 +249,10 @@ void RasterStrokeGenerator::placeOver(const TRasterCM32P &out, } } else if (m_task == PAINTBRUSH) { if (!inPix->isPureInk()) continue; - bool changePaint = - !m_selective || (m_selective && outPix->getPaint() == 0); + int paintIdx = outPix->getPaint(); + bool changePaint = (!m_selective && !m_modifierLockAlpha) || + (m_selective && paintIdx == 0) || + (m_modifierLockAlpha && paintIdx != 0); if (m_colorType == INK) *outPix = TPixelCM32(inPix->getInk(), outPix->getPaint(), outPix->getTone());