Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "fullcolorbrushtool.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzTools includes
Toshihiro Shimizu 890ddd
#include "tools/tool.h"
Toshihiro Shimizu 890ddd
#include "tools/cursors.h"
Toshihiro Shimizu 890ddd
#include "tools/toolutils.h"
Toshihiro Shimizu 890ddd
#include "tools/toolhandle.h"
Toshihiro Shimizu 890ddd
#include "tools/tooloptions.h"
Toshihiro Shimizu 890ddd
bf1d82
#include "mypainttoonzbrush.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzQt includes
Toshihiro Shimizu 890ddd
#include "toonzqt/dvdialog.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzLib includes
Toshihiro Shimizu 890ddd
#include "toonz/tpalettehandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/txsheethandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshlevelhandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tobjecthandle.h"
shun-iwasawa e1ab6d
#include "toonz/tframehandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/ttileset.h"
Toshihiro Shimizu 890ddd
#include "toonz/ttilesaver.h"
Toshihiro Shimizu 890ddd
#include "toonz/strokegenerator.h"
Toshihiro Shimizu 890ddd
#include "toonz/tstageobject.h"
Toshihiro Shimizu 890ddd
#include "toonz/palettecontroller.h"
bf1d82
#include "toonz/mypaintbrushstyle.h"
manongjohn 75da26
#include "toonz/preferences.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tgl.h"
Toshihiro Shimizu 890ddd
#include "tproperty.h"
Toshihiro Shimizu 890ddd
#include "trasterimage.h"
Toshihiro Shimizu 890ddd
#include "tenv.h"
Toshihiro Shimizu 890ddd
#include "tpalette.h"
Toshihiro Shimizu 890ddd
#include "trop.h"
Toshihiro Shimizu 890ddd
#include "tstream.h"
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
#include "timagecache.h"
bf1d82
#include "tpixelutils.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Qt includes
Shinya Kitaoka 120a6e
#include <qcoreapplication>  // Qt translation support</qcoreapplication>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TEnv::IntVar FullcolorBrushMinSize("FullcolorBrushMinSize", 1);
Toshihiro Shimizu 890ddd
TEnv::IntVar FullcolorBrushMaxSize("FullcolorBrushMaxSize", 5);
Campbell Barton f49389
TEnv::IntVar FullcolorPressureSensitivity("FullcolorPressureSensitivity", 1);
Toshihiro Shimizu 890ddd
TEnv::DoubleVar FullcolorBrushHardness("FullcolorBrushHardness", 100);
Toshihiro Shimizu 890ddd
TEnv::DoubleVar FullcolorMinOpacity("FullcolorMinOpacity", 100);
Toshihiro Shimizu 890ddd
TEnv::DoubleVar FullcolorMaxOpacity("FullcolorMaxOpacity", 100);
bf1d82
TEnv::DoubleVar FullcolorModifierSize("FullcolorModifierSize", 0);
bf1d82
TEnv::DoubleVar FullcolorModifierOpacity("FullcolorModifierOpacity", 100);
572ed1
TEnv::IntVar FullcolorModifierEraser("FullcolorModifierEraser", 0);
572ed1
TEnv::IntVar FullcolorModifierLockAlpha("FullcolorModifierLockAlpha", 0);
manongjohn df5842
TEnv::StringVar FullcolorBrushPreset("FullcolorBrushPreset", "<custom>");</custom>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define CUSTOM_WSTR L"<custom>"</custom>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Shinya Kitaoka 120a6e
Shinya Kitaoka d1f6c4
class FullColorBrushUndo final : public ToolUtils::TFullColorRasterUndo {
Shinya Kitaoka 120a6e
  TPoint m_offset;
Shinya Kitaoka 120a6e
  QString m_id;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  FullColorBrushUndo(TTileSetFullColor *tileSet, TXshSimpleLevel *level,
Shinya Kitaoka 120a6e
                     const TFrameId &frameId, bool isFrameCreated,
Shinya Kitaoka 120a6e
                     const TRasterP &ras, const TPoint &offset)
Shinya Kitaoka 120a6e
      : ToolUtils::TFullColorRasterUndo(tileSet, level, frameId, isFrameCreated,
Shinya Kitaoka 120a6e
                                        false, 0)
Shinya Kitaoka 120a6e
      , m_offset(offset) {
Shinya Kitaoka 120a6e
    static int counter = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_id = QString("FullColorBrushUndo") + QString::number(counter++);
Shinya Kitaoka 120a6e
    TImageCache::instance()->add(m_id.toStdString(), TRasterImageP(ras));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ~FullColorBrushUndo() { TImageCache::instance()->remove(m_id); }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void redo() const override {
Shinya Kitaoka 120a6e
    insertLevelAndFrameIfNeeded();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TRasterImageP image = getImage();
Shinya Kitaoka 120a6e
    TRasterP ras        = image->getRaster();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TRasterImageP srcImg =
Shinya Kitaoka 120a6e
        TImageCache::instance()->get(m_id.toStdString(), false);
Shinya Kitaoka 120a6e
    ras->copy(srcImg->getRaster(), m_offset);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged();
Shinya Kitaoka 120a6e
    notifyImageChanged();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  int getSize() const override {
Shinya Kitaoka 120a6e
    return sizeof(*this) + ToolUtils::TFullColorRasterUndo::getSize();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  QString getToolName() override { return QString("Raster Brush Tool"); }
Shinya Kitaoka 473e70
  int getHistoryType() override { return HistoryType::BrushTool; }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
//    FullColor Brush Tool implementation
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 3bfa54
FullColorBrushTool::FullColorBrushTool(std::string name)
Shinya Kitaoka 120a6e
    : TTool(name)
shun-iwasawa 76d093
    , m_thickness("Size", 1, 1000, 1, 5, false)
Jeremy Bullock 01e454
    , m_pressure("Pressure", true)
Jeremy Bullock 01e454
    , m_opacity("Opacity", 0, 100, 100, 100, true)
Shinya Kitaoka 120a6e
    , m_hardness("Hardness:", 0, 100, 100)
bf1d82
    , m_modifierSize("ModifierSize", -3, 3, 0, true)
bf1d82
    , m_modifierOpacity("ModifierOpacity", 0, 100, 100, true)
572ed1
    , m_modifierEraser("ModifierEraser", false)
manongjohn 963976
    , m_modifierLockAlpha("Lock Alpha", false)
Shinya Kitaoka 120a6e
    , m_preset("Preset:")
d8eddc
    , m_enabledPressure(false)
bf1d82
    , m_minCursorThick(0)
bf1d82
    , m_maxCursorThick(0)
bf1d82
    , m_toonz_brush(0)
Shinya Kitaoka 120a6e
    , m_tileSet(0)
Shinya Kitaoka 120a6e
    , m_tileSaver(0)
Shinya Kitaoka 120a6e
    , m_notifier(0)
Shinya Kitaoka 120a6e
    , m_presetsLoaded(false)
Shinya Kitaoka 120a6e
    , m_firstTime(true) {
Shinya Kitaoka 120a6e
  bind(TTool::RasterImage | TTool::EmptyTarget);
Shinya Kitaoka 120a6e
d8eddc
  m_inputmanager.setHandler(this);
d8eddc
  m_modifierTest = new TModifierTest();
d8eddc
  m_modifierTangents = new TModifierTangents();
d8eddc
  m_modifierSegmentation = new TModifierSegmentation();
d8eddc
  
shun-iwasawa 76d093
  m_thickness.setNonLinearSlider();
shun-iwasawa 76d093
Shinya Kitaoka 120a6e
  m_prop.bind(m_thickness);
Shinya Kitaoka 120a6e
  m_prop.bind(m_hardness);
Shinya Kitaoka 120a6e
  m_prop.bind(m_opacity);
bf1d82
  m_prop.bind(m_modifierSize);
bf1d82
  m_prop.bind(m_modifierOpacity);
572ed1
  m_prop.bind(m_modifierEraser);
572ed1
  m_prop.bind(m_modifierLockAlpha);
Shinya Kitaoka 120a6e
  m_prop.bind(m_pressure);
Shinya Kitaoka 120a6e
  m_prop.bind(m_preset);
bf1d82
Shinya Kitaoka 120a6e
  m_preset.setId("BrushPreset");
manongjohn 85ae4c
  m_modifierEraser.setId("RasterEraser");
manongjohn 85ae4c
  m_modifierLockAlpha.setId("LockAlpha");
manongjohn 85ae4c
  m_pressure.setId("PressureSensitivity");
bf1d82
bf1d82
  m_brushTimer.start();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
ToolOptionsBox *FullColorBrushTool::createOptionsBox() {
Shinya Kitaoka 120a6e
  TPaletteHandle *currPalette =
Shinya Kitaoka 120a6e
      TTool::getApplication()->getPaletteController()->getCurrentLevelPalette();
Shinya Kitaoka 120a6e
  ToolHandle *currTool = TTool::getApplication()->getCurrentTool();
Shinya Kitaoka 120a6e
  return new BrushToolOptionsBox(0, this, currPalette, currTool);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::onCanvasSizeChanged() {
Shinya Kitaoka 120a6e
  onDeactivate();
Shinya Kitaoka 120a6e
  setWorkAndBackupImages();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
bf1d82
void FullColorBrushTool::onColorStyleChanged() {
bf1d82
  getApplication()->getCurrentTool()->notifyToolChanged();
bf1d82
}
bf1d82
bf1d82
//---------------------------------------------------------------------------------------------------
bf1d82
Shinya Kitaoka 120a6e
void FullColorBrushTool::updateTranslation() {
Jeremy Bullock 01e454
  m_thickness.setQStringName(tr("Size"));
Jeremy Bullock 01e454
  m_pressure.setQStringName(tr("Pressure"));
Jeremy Bullock 01e454
  m_opacity.setQStringName(tr("Opacity"));
Shinya Kitaoka 120a6e
  m_hardness.setQStringName(tr("Hardness:"));
Shinya Kitaoka 120a6e
  m_preset.setQStringName(tr("Preset:"));
bf1d82
  m_modifierSize.setQStringName(tr("Size"));
bf1d82
  m_modifierOpacity.setQStringName(tr("Opacity"));
572ed1
  m_modifierEraser.setQStringName(tr("Eraser"));
572ed1
  m_modifierLockAlpha.setQStringName(tr("Lock Alpha"));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::onActivate() {
Shinya Kitaoka 120a6e
  if (!m_notifier) m_notifier = new FullColorBrushToolNotifier(this);
Shinya Kitaoka 120a6e
bf1d82
  updateCurrentStyle();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_firstTime) {
Shinya Kitaoka 120a6e
    m_firstTime = false;
manongjohn df5842
manongjohn df5842
    std::wstring wpreset =
manongjohn df5842
        QString::fromStdString(FullcolorBrushPreset.getValue()).toStdWString();
manongjohn df5842
    if (wpreset != CUSTOM_WSTR) {
manongjohn df5842
      initPresets();
manongjohn 8b8d41
      if (!m_preset.isValue(wpreset)) wpreset = CUSTOM_WSTR;
manongjohn df5842
      m_preset.setValue(wpreset);
manongjohn 8b8d41
      FullcolorBrushPreset = m_preset.getValueAsString();
manongjohn df5842
      loadPreset();
manongjohn df5842
    } else
manongjohn df5842
      loadLastBrush();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  setWorkAndBackupImages();
bf1d82
  onColorStyleChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::onDeactivate() {
d8eddc
  m_inputmanager.finishTracks();
Shinya Kitaoka 120a6e
  m_workRaster = TRaster32P();
Shinya Kitaoka 120a6e
  m_backUpRas  = TRasterP();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::updateWorkAndBackupRasters(const TRect &rect) {
bf1d82
  if (rect.isEmpty()) return;
bf1d82
Shinya Kitaoka 120a6e
  TRasterImageP ri = TImageP(getImage(false, 1));
Shinya Kitaoka 120a6e
  if (!ri) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRasterP ras = ri->getRaster();
Toshihiro Shimizu 890ddd
bf1d82
  const int denominator = 8;
shun_iwasawa e553fc
  TRect enlargedRect    = rect + m_lastRect;
shun_iwasawa e553fc
  int dx                = (enlargedRect.getLx() - 1) / denominator + 1;
shun_iwasawa e553fc
  int dy                = (enlargedRect.getLy() - 1) / denominator + 1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_lastRect.isEmpty()) {
bf1d82
    enlargedRect.x0 -= dx;
bf1d82
    enlargedRect.y0 -= dy;
bf1d82
    enlargedRect.x1 += dx;
bf1d82
    enlargedRect.y1 += dy;
bf1d82
shun_iwasawa e553fc
    TRect _rect = enlargedRect * ras->getBounds();
bf1d82
    if (_rect.isEmpty()) return;
bf1d82
bf1d82
    m_workRaster->extract(_rect)->copy(ras->extract(_rect));
Shinya Kitaoka 120a6e
    m_backUpRas->extract(_rect)->copy(ras->extract(_rect));
bf1d82
  } else {
bf1d82
    if (enlargedRect.x0 < m_lastRect.x0) enlargedRect.x0 -= dx;
bf1d82
    if (enlargedRect.y0 < m_lastRect.y0) enlargedRect.y0 -= dy;
bf1d82
    if (enlargedRect.x1 > m_lastRect.x1) enlargedRect.x1 += dx;
bf1d82
    if (enlargedRect.y1 > m_lastRect.y1) enlargedRect.y1 += dy;
bf1d82
shun_iwasawa e553fc
    TRect _rect = enlargedRect * ras->getBounds();
bf1d82
    if (_rect.isEmpty()) return;
bf1d82
shun_iwasawa e553fc
    TRect _lastRect    = m_lastRect * ras->getBounds();
bf1d82
    QList<trect> rects = ToolUtils::splitRect(_rect, _lastRect);</trect>
bf1d82
    for (int i = 0; i < rects.size(); i++) {
bf1d82
      m_workRaster->extract(rects[i])->copy(ras->extract(rects[i]));
bf1d82
      m_backUpRas->extract(rects[i])->copy(ras->extract(rects[i]));
bf1d82
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
bf1d82
  m_lastRect = enlargedRect;
bf1d82
}
bf1d82
bf1d82
//--------------------------------------------------------------------------------------------------
bf1d82
shun_iwasawa e553fc
bool FullColorBrushTool::askRead(const TRect &rect) { return askWrite(rect); }
bf1d82
bf1d82
//--------------------------------------------------------------------------------------------------
bf1d82
bf1d82
bool FullColorBrushTool::askWrite(const TRect &rect) {
bf1d82
  if (rect.isEmpty()) return true;
bf1d82
  m_strokeRect += rect;
bf1d82
  m_strokeSegmentRect += rect;
bf1d82
  updateWorkAndBackupRasters(rect);
bf1d82
  m_tileSaver->save(rect);
bf1d82
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool FullColorBrushTool::preLeftButtonDown() {
d8eddc
  m_inputmanager.clearModifiers();
d8eddc
  m_inputmanager.addModifier( TInputModifierP(m_modifierTangents.getPointer()) );
d8eddc
  m_inputmanager.addModifier( TInputModifierP(m_modifierSegmentation.getPointer()) );
d8eddc
  m_inputmanager.addModifier( TInputModifierP(m_modifierTest.getPointer()) );
d8eddc
  
Shinya Kitaoka 120a6e
  touchImage();
Toshihiro Shimizu 890ddd
shun-iwasawa e1ab6d
  if (m_isFrameCreated) {
shun-iwasawa e1ab6d
    setWorkAndBackupImages();
shun-iwasawa e1ab6d
    // When the xsheet frame is selected, whole viewer will be updated from
shun-iwasawa e1ab6d
    // SceneViewer::onXsheetChanged() on adding a new frame.
shun-iwasawa e1ab6d
    // We need to take care of a case when the level frame is selected.
shun-iwasawa e1ab6d
    if (m_application->getCurrentFrame()->isEditingLevel()) invalidate();
shun-iwasawa e1ab6d
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
d8eddc
void FullColorBrushTool::handleMouseEvent(MouseEventType type, const TPointD &pos, const TMouseEvent &e) {
d8eddc
  TTimerTicks t = TToolTimer::ticks();
d8eddc
  bool alt = e.getModifiersMask() & TMouseEvent::ALT_KEY;
d8eddc
  bool shift = e.getModifiersMask() & TMouseEvent::SHIFT_KEY;
d8eddc
  bool control = e.getModifiersMask() & TMouseEvent::CTRL_KEY;
d8eddc
  if (alt != m_inputmanager.state.isKeyPressed(TKey::alt))
d8eddc
    m_inputmanager.keyEvent(alt, TKey::alt, t, nullptr);
d8eddc
  if (shift != m_inputmanager.state.isKeyPressed(TKey::shift))
d8eddc
    m_inputmanager.keyEvent(shift, TKey::shift, t, nullptr);
d8eddc
  if (control != m_inputmanager.state.isKeyPressed(TKey::control))
d8eddc
    m_inputmanager.keyEvent(control, TKey::control, t, nullptr);
d8eddc
  
d8eddc
  if (type == ME_MOVE) {
d8eddc
    THoverList hovers(1, pos);
d8eddc
    m_inputmanager.hoverEvent(hovers);
d8eddc
  } else {
d8eddc
    m_inputmanager.trackEvent(
d8eddc
      e.isTablet(), 0, pos,
d8eddc
      e.isTablet() ? &e.m_pressure : nullptr, nullptr,
d8eddc
      type == ME_UP, t );
d8eddc
    m_inputmanager.processTracks();
d8eddc
  }
d8eddc
}
d8eddc
d8eddc
//---------------------------------------------------------------------------------------------------
d8eddc
d8eddc
void FullColorBrushTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e)
d8eddc
  { handleMouseEvent(ME_DOWN, pos, e); }
d8eddc
void FullColorBrushTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &e)
d8eddc
  { handleMouseEvent(ME_DRAG, pos, e); }
d8eddc
void FullColorBrushTool::leftButtonUp(const TPointD &pos, const TMouseEvent &e)
d8eddc
  { handleMouseEvent(ME_UP, pos, e); }
d8eddc
void FullColorBrushTool::mouseMove(const TPointD &pos, const TMouseEvent &e)
d8eddc
  { handleMouseEvent(ME_MOVE, pos, e); }
d8eddc
d8eddc
//---------------------------------------------------------------------------------------------------
d8eddc
d8eddc
void FullColorBrushTool::inputLeftButtonDown(
d8eddc
  const TTrackPoint &point, const TTrack &track )
d8eddc
{
d8eddc
  const TPointD &pos = point.position;
bf1d82
  TPointD previousBrushPos = m_brushPos;
Shinya Kitaoka 120a6e
  m_brushPos = m_mousePos = pos;
Jeremy Bullock 5af997
  m_mousePressed          = true;
Jeremy Bullock 5af997
  Viewer *viewer          = getViewer();
Shinya Kitaoka 120a6e
  if (!viewer) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRasterImageP ri = (TRasterImageP)getImage(true);
shun-iwasawa e1ab6d
  if (!ri) ri = (TRasterImageP)touchImage();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!ri) return;
Shinya Kitaoka 120a6e
justburner e250b7
  // Modifier to do straight line
d8eddc
  TInputState::KeyState::Holder keys = track.getKeyState(point);
d8eddc
  if (keys.isPressed(TKey::shift) || keys.isPressed(TKey::control)) {
justburner e250b7
    m_isStraight = true;
justburner e250b7
    m_firstPoint = pos;
justburner e250b7
    m_lastPoint  = pos;
justburner e250b7
  }
justburner e250b7
shun_iwasawa e3df22
  /* update color here since the current style might be switched with numpad
shun_iwasawa e3df22
   * shortcut keys */
bf1d82
  updateCurrentStyle();
shun_iwasawa e3df22
bf1d82
  TRasterP ras = ri->getRaster();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!(m_workRaster && m_backUpRas)) setWorkAndBackupImages();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_workRaster->lock();
Shinya Kitaoka 120a6e
bf1d82
  TPointD rasCenter = ras->getCenterD();
d8eddc
  TPointD pt(pos + rasCenter);
shun-iwasawa 76d093
d8eddc
  double defPressure = 1.0;
d8eddc
  if (getApplication()->getCurrentLevelStyle()->getTagId() == 4001) // mypaint brush case
d8eddc
    defPressure = 0.5;
d8eddc
  double pressure = m_enabledPressure && track.hasPressure ? point.pressure : defPressure;
Shinya Kitaoka 120a6e
shun_iwasawa e553fc
  m_tileSet   = new TTileSetFullColor(ras->getSize());
shun_iwasawa e553fc
  m_tileSaver = new TTileSaverFullColor(ras, m_tileSet);
bf1d82
bf1d82
  mypaint::Brush mypaintBrush;
bf1d82
  applyToonzBrushSettings(mypaintBrush);
d8eddc
  m_toonz_brush = new MyPaintToonzBrush(m_workRaster, *this, mypaintBrush, false);
bf1d82
bf1d82
  m_strokeRect.empty();
bf1d82
  m_strokeSegmentRect.empty();
bf1d82
  m_toonz_brush->beginStroke();
d8eddc
  m_toonz_brush->strokeTo(pt, pressure, restartBrushTimer());
shun_iwasawa e553fc
  TRect updateRect = m_strokeSegmentRect * ras->getBounds();
bf1d82
  if (!updateRect.isEmpty())
bf1d82
    ras->extract(updateRect)->copy(m_workRaster->extract(updateRect));
bf1d82
shun_iwasawa e553fc
  TPointD thickOffset(m_maxCursorThick * 0.5, m_maxCursorThick * 0.5);
bf1d82
  TRectD invalidateRect = convert(m_strokeSegmentRect) - rasCenter;
bf1d82
  invalidateRect += TRectD(m_brushPos - thickOffset, m_brushPos + thickOffset);
shun_iwasawa e553fc
  invalidateRect +=
shun_iwasawa e553fc
      TRectD(previousBrushPos - thickOffset, previousBrushPos + thickOffset);
bf1d82
  invalidate(invalidateRect.enlarge(2.0));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
d8eddc
void FullColorBrushTool::inputLeftButtonDrag(
d8eddc
  const TTrackPoint &point, const TTrack &track )
d8eddc
{
d8eddc
  const TPointD &pos = point.position;
justburner e250b7
  TRectD invalidateRect;
d8eddc
  TPointD previousLastPoint = m_lastPoint;
justburner e250b7
  m_lastPoint = pos;
justburner e250b7
bf1d82
  TPointD previousBrushPos = m_brushPos;
Shinya Kitaoka 120a6e
  m_brushPos = m_mousePos = pos;
Jeremy Bullock 5af997
  TRasterImageP ri        = (TRasterImageP)getImage(true);
Shinya Kitaoka 120a6e
  if (!ri) return;
Shinya Kitaoka 120a6e
manongjohn 5ed362
  if (!m_toonz_brush) return;
manongjohn 5ed362
shun_iwasawa e553fc
  TRasterP ras      = ri->getRaster();
bf1d82
  TPointD rasCenter = ras->getCenterD();
d8eddc
  TPointD pt(pos + rasCenter);
d8eddc
d8eddc
  double defPressure = 1.0;
d8eddc
  if (getApplication()->getCurrentLevelStyle()->getTagId() == 4001) // mypaint brush case
d8eddc
    defPressure = 0.5;
d8eddc
  double pressure = m_enabledPressure && track.hasPressure ? point.pressure : defPressure;
bf1d82
justburner e250b7
  if (m_maxPressure < pressure) m_maxPressure = pressure;
justburner e250b7
justburner e250b7
  if (m_isStraight) {
d8eddc
    if (track.getKeyState(point).isPressed(TKey::control)) {
d8eddc
      TPointD dist = m_lastPoint - m_firstPoint;
d8eddc
      double angle = fabs(atan(dist)) * (180 / 3.14159);
d8eddc
      if (angle > 90) angle = 180 - angle;
d8eddc
      if (angle > 90 - 22.5)
justburner e250b7
        m_lastPoint.x = m_firstPoint.x;
d8eddc
      else if (angle < 22.5)
justburner e250b7
        m_lastPoint.y = m_firstPoint.y;
justburner e250b7
      else {
justburner e250b7
        double xDistance = m_lastPoint.x - m_firstPoint.x;
justburner e250b7
        double yDistance = m_lastPoint.y - m_firstPoint.y;
justburner e250b7
        if (abs(xDistance) > abs(yDistance)) {
justburner e250b7
          if (abs(yDistance) == yDistance)
justburner e250b7
            m_lastPoint.y = m_firstPoint.y + abs(xDistance);
justburner e250b7
          else
justburner e250b7
            m_lastPoint.y = m_firstPoint.y - abs(xDistance);
justburner e250b7
        } else {
justburner e250b7
          if (abs(xDistance) == xDistance)
justburner e250b7
            m_lastPoint.x = m_firstPoint.x + abs(yDistance);
justburner e250b7
          else
justburner e250b7
            m_lastPoint.x = m_firstPoint.x - abs(yDistance);
justburner e250b7
        }
justburner e250b7
      }
justburner e250b7
    }
d8eddc
    double cursorSize = m_maxCursorThick/2 + 2;
d8eddc
    TPointD cursorSize2d(cursorSize, cursorSize);
d8eddc
    invalidateRect = TRectD(m_firstPoint, previousLastPoint).enlarge(2);
d8eddc
    invalidateRect += TRectD(previousBrushPos - cursorSize2d, previousBrushPos + cursorSize2d);
d8eddc
    invalidateRect += TRectD(m_brushPos - cursorSize2d, m_brushPos + cursorSize2d);
d8eddc
    invalidateRect += TRectD(m_firstPoint, m_lastPoint).enlarge(2);
justburner e250b7
    invalidate(invalidateRect);
justburner e250b7
    return;
justburner e250b7
  }
justburner e250b7
bf1d82
  m_strokeSegmentRect.empty();
d8eddc
  m_toonz_brush->strokeTo(pt, pressure, restartBrushTimer());
shun_iwasawa e553fc
  TRect updateRect = m_strokeSegmentRect * ras->getBounds();
bf1d82
  if (!updateRect.isEmpty())
bf1d82
    ras->extract(updateRect)->copy(m_workRaster->extract(updateRect));
bf1d82
shun_iwasawa e553fc
  TPointD thickOffset(m_maxCursorThick * 0.5, m_maxCursorThick * 0.5);
justburner e250b7
  invalidateRect = convert(m_strokeSegmentRect) - rasCenter;
bf1d82
  invalidateRect += TRectD(m_brushPos - thickOffset, m_brushPos + thickOffset);
shun_iwasawa e553fc
  invalidateRect +=
shun_iwasawa e553fc
      TRectD(previousBrushPos - thickOffset, previousBrushPos + thickOffset);
bf1d82
  invalidate(invalidateRect.enlarge(2.0));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
d8eddc
void FullColorBrushTool::inputLeftButtonUp(
d8eddc
  const TTrackPoint &point, const TTrack &track )
d8eddc
{
d8eddc
  const TPointD &pos = point.position;
bf1d82
  TPointD previousBrushPos = m_brushPos;
Shinya Kitaoka 120a6e
  m_brushPos = m_mousePos = pos;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRasterImageP ri = (TRasterImageP)getImage(true);
Shinya Kitaoka 120a6e
  if (!ri) return;
Shinya Kitaoka 120a6e
manongjohn 648efa
  if (!m_toonz_brush) return;
manongjohn 648efa
shun_iwasawa e553fc
  TRasterP ras      = ri->getRaster();
bf1d82
  TPointD rasCenter = ras->getCenterD();
d8eddc
  TPointD pt;
justburner e250b7
  if (m_isStraight)
d8eddc
    pt = TPointD(m_lastPoint + rasCenter);
shun-iwasawa 76d093
  else
d8eddc
    pt = TPointD(pos + rasCenter);
bf1d82
d8eddc
  double defPressure = 1.0;
d8eddc
  if (getApplication()->getCurrentLevelStyle()->getTagId() == 4001) // mypaint brush case
d8eddc
    defPressure = 0.5;
d8eddc
  double pressure = m_enabledPressure && track.hasPressure ? point.pressure : defPressure;
d8eddc
d8eddc
  if (m_isStraight && m_maxPressure > 0.0)
justburner e250b7
    pressure = m_maxPressure;
justburner e250b7
bf1d82
  m_strokeSegmentRect.empty();
d8eddc
  m_toonz_brush->strokeTo(pt, pressure, restartBrushTimer());
bf1d82
  m_toonz_brush->endStroke();
shun_iwasawa e553fc
  TRect updateRect = m_strokeSegmentRect * ras->getBounds();
bf1d82
  if (!updateRect.isEmpty())
bf1d82
    ras->extract(updateRect)->copy(m_workRaster->extract(updateRect));
bf1d82
shun_iwasawa e553fc
  TPointD thickOffset(m_maxCursorThick * 0.5, m_maxCursorThick * 0.5);
bf1d82
  TRectD invalidateRect = convert(m_strokeSegmentRect) - rasCenter;
bf1d82
  invalidateRect += TRectD(m_brushPos - thickOffset, m_brushPos + thickOffset);
shun_iwasawa e553fc
  invalidateRect +=
shun_iwasawa e553fc
      TRectD(previousBrushPos - thickOffset, previousBrushPos + thickOffset);
bf1d82
  invalidate(invalidateRect.enlarge(2.0));
bf1d82
bf1d82
  if (m_toonz_brush) {
bf1d82
    delete m_toonz_brush;
bf1d82
    m_toonz_brush = 0;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
bf1d82
  m_lastRect.empty();
Shinya Kitaoka 120a6e
  m_workRaster->unlock();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_tileSet->getTileCount() > 0) {
Shinya Kitaoka 120a6e
    delete m_tileSaver;
Shinya Kitaoka 120a6e
    TTool::Application *app   = TTool::getApplication();
Shinya Kitaoka 120a6e
    TXshLevel *level          = app->getCurrentLevel()->getLevel();
Shinya Kitaoka 120a6e
    TXshSimpleLevelP simLevel = level->getSimpleLevel();
Shinya Kitaoka 120a6e
    TFrameId frameId          = getCurrentFid();
bf1d82
    TRasterP subras           = ras->extract(m_strokeRect)->clone();
shun_iwasawa e553fc
    TUndoManager::manager()->add(new FullColorBrushUndo(
shun_iwasawa e553fc
        m_tileSet, simLevel.getPointer(), frameId, m_isFrameCreated, subras,
shun_iwasawa e553fc
        m_strokeRect.getP00()));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  notifyImageChanged();
Shinya Kitaoka 120a6e
  m_strokeRect.empty();
Jeremy Bullock 5af997
  m_mousePressed = false;
justburner e250b7
  m_isStraight   = false;
justburner e250b7
  m_maxPressure  = -1.0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
d8eddc
void FullColorBrushTool::inputMouseMove(
d8eddc
  const TPointD &position, const TInputState &state )
d8eddc
{
Shinya Kitaoka 120a6e
  struct Locals {
Shinya Kitaoka 120a6e
    FullColorBrushTool *m_this;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    void setValue(TIntPairProperty &prop,
Shinya Kitaoka 120a6e
                  const TIntPairProperty::Value &value) {
Shinya Kitaoka 120a6e
      prop.setValue(value);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      m_this->onPropertyChanged(prop.getName());
Shinya Kitaoka 120a6e
      TTool::getApplication()->getCurrentTool()->notifyToolChanged();
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    void addMinMax(TIntPairProperty &prop, double add) {
Shinya Kitaoka 120a6e
      const TIntPairProperty::Range &range = prop.getRange();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      TIntPairProperty::Value value = prop.getValue();
Shinya Kitaoka 120a6e
      value.second =
Shinya Kitaoka 120a6e
          tcrop<double>(value.second + add, range.first, range.second);</double>
Shinya Kitaoka 120a6e
      value.first = tcrop<double>(value.first + add, range.first, range.second);</double>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      setValue(prop, value);
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Jeremy Bullock 01e454
    void addMinMaxSeparate(TIntPairProperty &prop, double min, double max) {
Jeremy Bullock 01e454
      if (min == 0.0 && max == 0.0) return;
Jeremy Bullock 01e454
      const TIntPairProperty::Range &range = prop.getRange();
Toshihiro Shimizu 890ddd
Jeremy Bullock 01e454
      TIntPairProperty::Value value = prop.getValue();
Jeremy Bullock 01e454
      value.first += min;
Jeremy Bullock 01e454
      value.second += max;
Jeremy Bullock 01e454
      if (value.first > value.second) value.first = value.second;
Jeremy Bullock 01e454
      value.first  = tcrop<double>(value.first, range.first, range.second);</double>
Jeremy Bullock 01e454
      value.second = tcrop<double>(value.second, range.first, range.second);</double>
Jeremy Bullock 01e454
Jeremy Bullock 01e454
      setValue(prop, value);
Jeremy Bullock 01e454
    }
Jeremy Bullock 01e454
  } locals = {this};
Shinya Kitaoka d4642c
d8eddc
  if (state.isKeyPressed(TKey::control) && state.isKeyPressed(TKey::alt)) {
d8eddc
    const TPointD &diff = position - m_mousePos;
Jeremy Bullock 01e454
    double max          = diff.x / 2;
Jeremy Bullock 01e454
    double min          = diff.y / 2;
Jeremy Bullock 01e454
    locals.addMinMaxSeparate(m_thickness, int(min), int(max));
Jeremy Bullock 01e454
  } else {
d8eddc
    m_brushPos = position;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
d8eddc
  m_mousePos = position;
Shinya Kitaoka 120a6e
  invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------------------------
00337d
00337d
void FullColorBrushTool::inputInvalidateRect(const TRectD &bounds)
00337d
  { invalidate(bounds); }
00337d
00337d
//-------------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::draw() {
Shinya Kitaoka 120a6e
  if (TRasterImageP ri = TRasterImageP(getImage(false))) {
justburner e250b7
    // Draw line segment on straight line mode
justburner e250b7
    if (m_isStraight) {
justburner e250b7
      tglDrawSegment(m_firstPoint, m_lastPoint);
justburner e250b7
    }
justburner e250b7
manongjohn 75da26
    // If toggled off, don't draw brush outline
manongjohn 75da26
    if (!Preferences::instance()->isCursorOutlineEnabled()) return;
manongjohn 75da26
Shinya Kitaoka 120a6e
    TRasterP ras = ri->getRaster();
Toshihiro Shimizu 890ddd
shun_iwasawa e553fc
    double alpha       = 1.0;
bf1d82
    double alphaRadius = 3.0;
shun_iwasawa e553fc
    double pixelSize   = sqrt(tglGetPixelSize2());
bf1d82
bf1d82
    // circles with lesser radius looks more bold
bf1d82
    // to avoid these effect we'll reduce alpha for small radiuses
shun_iwasawa e553fc
    double minX     = m_minCursorThick / (alphaRadius * pixelSize);
shun_iwasawa e553fc
    double maxX     = m_maxCursorThick / (alphaRadius * pixelSize);
shun_iwasawa e553fc
    double minAlpha = alpha * (1.0 - 1.0 / (1.0 + minX));
shun_iwasawa e553fc
    double maxAlpha = alpha * (1.0 - 1.0 / (1.0 + maxX));
bf1d82
bf1d82
    glPushAttrib(GL_ALL_ATTRIB_BITS);
bf1d82
    tglEnableBlending();
bf1d82
    tglEnableLineSmooth(true, 0.5);
bf1d82
bf1d82
    if (m_minCursorThick < m_maxCursorThick - pixelSize) {
bf1d82
      glColor4d(1.0, 1.0, 1.0, minAlpha);
shun_iwasawa e553fc
      tglDrawCircle(m_brushPos, (m_minCursorThick + 1) * 0.5 - pixelSize);
bf1d82
      glColor4d(0.0, 0.0, 0.0, minAlpha);
shun_iwasawa e553fc
      tglDrawCircle(m_brushPos, (m_minCursorThick + 1) * 0.5);
bf1d82
    }
bf1d82
bf1d82
    glColor4d(1.0, 1.0, 1.0, maxAlpha);
shun_iwasawa e553fc
    tglDrawCircle(m_brushPos, (m_maxCursorThick + 1) * 0.5 - pixelSize);
bf1d82
    glColor4d(0.0, 0.0, 0.0, maxAlpha);
shun_iwasawa e553fc
    tglDrawCircle(m_brushPos, (m_maxCursorThick + 1) * 0.5);
Toshihiro Shimizu 890ddd
bf1d82
    glPopAttrib();
Shinya Kitaoka 120a6e
  }
c3c215
  m_inputmanager.draw();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
shun_iwasawa e553fc
void FullColorBrushTool::onEnter() { updateCurrentStyle(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::onLeave() {
bf1d82
  m_minCursorThick = 0;
bf1d82
  m_maxCursorThick = 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TPropertyGroup *FullColorBrushTool::getProperties(int targetType) {
Shinya Kitaoka 120a6e
  if (!m_presetsLoaded) initPresets();
Shinya Kitaoka 120a6e
  return &m_prop;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::onImageChanged() { setWorkAndBackupImages(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::setWorkAndBackupImages() {
Shinya Kitaoka 120a6e
  TRasterImageP ri = (TRasterImageP)getImage(false, 1);
Shinya Kitaoka 120a6e
  if (!ri) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRasterP ras   = ri->getRaster();
Shinya Kitaoka 120a6e
  TDimension dim = ras->getSize();
Toshihiro Shimizu 890ddd
Jeremy Bullock 8c1a46
  if (!m_workRaster || m_workRaster->getLx() != dim.lx ||
Jeremy Bullock 8c1a46
      m_workRaster->getLy() != dim.ly)
Shinya Kitaoka 120a6e
    m_workRaster = TRaster32P(dim);
Toshihiro Shimizu 890ddd
Jeremy Bullock 8c1a46
  if (!m_backUpRas || m_backUpRas->getLx() != dim.lx ||
Jeremy Bullock 8c1a46
      m_backUpRas->getLy() != dim.ly ||
Shinya Kitaoka 120a6e
      m_backUpRas->getPixelSize() != ras->getPixelSize())
Shinya Kitaoka 120a6e
    m_backUpRas = ras->create(dim.lx, dim.ly);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_strokeRect.empty();
Shinya Kitaoka 120a6e
  m_lastRect.empty();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool FullColorBrushTool::onPropertyChanged(std::string propertyName) {
manongjohn 5a2268
  if (m_propertyUpdating) return true;
manongjohn 5a2268
manongjohn df5842
  updateCurrentStyle();
manongjohn df5842
manongjohn df5842
  if (propertyName == "Preset:") {
manongjohn df5842
    if (m_preset.getValue() != CUSTOM_WSTR)
manongjohn df5842
      loadPreset();
manongjohn df5842
    else  // Chose <custom>, go back to last saved brush settings</custom>
manongjohn df5842
      loadLastBrush();
manongjohn df5842
manongjohn df5842
    FullcolorBrushPreset = m_preset.getValueAsString();
manongjohn 5a2268
    m_propertyUpdating   = true;
manongjohn df5842
    getApplication()->getCurrentTool()->notifyToolChanged();
manongjohn 5a2268
    m_propertyUpdating = false;
manongjohn df5842
    return true;
manongjohn df5842
  }
manongjohn df5842
bf1d82
  FullcolorBrushMinSize        = m_thickness.getValue().first;
bf1d82
  FullcolorBrushMaxSize        = m_thickness.getValue().second;
Campbell Barton f49389
  FullcolorPressureSensitivity = m_pressure.getValue();
Shinya Kitaoka 120a6e
  FullcolorBrushHardness       = m_hardness.getValue();
Shinya Kitaoka 120a6e
  FullcolorMinOpacity          = m_opacity.getValue().first;
Shinya Kitaoka 120a6e
  FullcolorMaxOpacity          = m_opacity.getValue().second;
bf1d82
  FullcolorModifierSize        = m_modifierSize.getValue();
bf1d82
  FullcolorModifierOpacity     = m_modifierOpacity.getValue();
572ed1
  FullcolorModifierEraser      = m_modifierEraser.getValue() ? 1 : 0;
572ed1
  FullcolorModifierLockAlpha   = m_modifierLockAlpha.getValue() ? 1 : 0;
bf1d82
Shinya Kitaoka 120a6e
  if (m_preset.getValue() != CUSTOM_WSTR) {
Shinya Kitaoka 120a6e
    m_preset.setValue(CUSTOM_WSTR);
manongjohn df5842
    FullcolorBrushPreset = m_preset.getValueAsString();
manongjohn 5a2268
    m_propertyUpdating   = true;
Shinya Kitaoka 120a6e
    getApplication()->getCurrentTool()->notifyToolChanged();
manongjohn 5a2268
    m_propertyUpdating = false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::initPresets() {
Shinya Kitaoka 120a6e
  if (!m_presetsLoaded) {
Shinya Kitaoka 120a6e
    // If necessary, load the presets from file
Shinya Kitaoka 120a6e
    m_presetsLoaded = true;
Shinya Kitaoka 120a6e
    m_presetsManager.load(TEnv::getConfigDir() + "brush_raster.txt");
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Rebuild the presets property entries
Shinya Kitaoka 120a6e
  const std::set<brushdata> &presets = m_presetsManager.presets();</brushdata>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_preset.deleteAllValues();
Shinya Kitaoka 120a6e
  m_preset.addValue(CUSTOM_WSTR);
shun-iwasawa e87e08
  m_preset.setItemUIName(CUSTOM_WSTR, tr("<custom>"));</custom>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::set<brushdata>::const_iterator it, end = presets.end();</brushdata>
Shinya Kitaoka 120a6e
  for (it = presets.begin(); it != end; ++it) m_preset.addValue(it->m_name);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::loadPreset() {
Shinya Kitaoka 120a6e
  const std::set<brushdata> &presets = m_presetsManager.presets();</brushdata>
Shinya Kitaoka 120a6e
  std::set<brushdata>::const_iterator it;</brushdata>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  it = presets.find(BrushData(m_preset.getValue()));
Shinya Kitaoka 120a6e
  if (it == presets.end()) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const BrushData &preset = *it;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  try  // Don't bother with RangeErrors
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    m_thickness.setValue(
Shinya Kitaoka 120a6e
        TIntPairProperty::Value(std::max((int)preset.m_min, 1), preset.m_max));
Shinya Kitaoka 120a6e
    m_hardness.setValue(preset.m_hardness, true);
Shinya Kitaoka 120a6e
    m_opacity.setValue(
Shinya Kitaoka 120a6e
        TDoublePairProperty::Value(preset.m_opacityMin, preset.m_opacityMax));
Shinya Kitaoka 120a6e
    m_pressure.setValue(preset.m_pressure);
bf1d82
    m_modifierSize.setValue(preset.m_modifierSize);
bf1d82
    m_modifierOpacity.setValue(preset.m_modifierOpacity);
572ed1
    m_modifierEraser.setValue(preset.m_modifierEraser);
572ed1
    m_modifierLockAlpha.setValue(preset.m_modifierLockAlpha);
Shinya Kitaoka 120a6e
  } catch (...) {
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::addPreset(QString name) {
Shinya Kitaoka 120a6e
  // Build the preset
Shinya Kitaoka 120a6e
  BrushData preset(name.toStdWString());
Toshihiro Shimizu 890ddd
572ed1
  preset.m_min               = m_thickness.getValue().first;
572ed1
  preset.m_max               = m_thickness.getValue().second;
572ed1
  preset.m_hardness          = m_hardness.getValue();
572ed1
  preset.m_opacityMin        = m_opacity.getValue().first;
572ed1
  preset.m_opacityMax        = m_opacity.getValue().second;
572ed1
  preset.m_pressure          = m_pressure.getValue();
572ed1
  preset.m_modifierSize      = m_modifierSize.getValue();
572ed1
  preset.m_modifierOpacity   = m_modifierOpacity.getValue();
572ed1
  preset.m_modifierEraser    = m_modifierEraser.getValue();
572ed1
  preset.m_modifierLockAlpha = m_modifierLockAlpha.getValue();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Pass the preset to the manager
Shinya Kitaoka 120a6e
  m_presetsManager.addPreset(preset);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Reinitialize the associated preset enum
Shinya Kitaoka 120a6e
  initPresets();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Set the value to the specified one
Shinya Kitaoka 120a6e
  m_preset.setValue(preset.m_name);
manongjohn 8b8d41
  FullcolorBrushPreset = m_preset.getValueAsString();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FullColorBrushTool::removePreset() {
Shinya Kitaoka 120a6e
  std::wstring name(m_preset.getValue());
Shinya Kitaoka 120a6e
  if (name == CUSTOM_WSTR) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_presetsManager.removePreset(name);
Shinya Kitaoka 120a6e
  initPresets();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // No parameter change, and set the preset value to custom
Shinya Kitaoka 120a6e
  m_preset.setValue(CUSTOM_WSTR);
manongjohn 8b8d41
  FullcolorBrushPreset = m_preset.getValueAsString();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
shun_iwasawa e3df22
//------------------------------------------------------------------
manongjohn df5842
manongjohn df5842
void FullColorBrushTool::loadLastBrush() {
manongjohn df5842
  m_thickness.setValue(
manongjohn df5842
      TIntPairProperty::Value(FullcolorBrushMinSize, FullcolorBrushMaxSize));
manongjohn df5842
  m_pressure.setValue(FullcolorPressureSensitivity ? 1 : 0);
manongjohn df5842
  m_opacity.setValue(
manongjohn df5842
      TDoublePairProperty::Value(FullcolorMinOpacity, FullcolorMaxOpacity));
manongjohn df5842
  m_hardness.setValue(FullcolorBrushHardness);
manongjohn df5842
  m_modifierSize.setValue(FullcolorModifierSize);
manongjohn df5842
  m_modifierOpacity.setValue(FullcolorModifierOpacity);
manongjohn df5842
  m_modifierEraser.setValue(FullcolorModifierEraser ? true : false);
manongjohn df5842
  m_modifierLockAlpha.setValue(FullcolorModifierLockAlpha ? true : false);
manongjohn df5842
}
manongjohn df5842
manongjohn df5842
//------------------------------------------------------------------
shun_iwasawa e3df22
bf1d82
void FullColorBrushTool::updateCurrentStyle() {
bf1d82
  m_currentColor = TPixel32::Black;
bf1d82
  if (TTool::Application *app = getApplication()) {
bf1d82
    if (app->getCurrentObject()->isSpline()) {
bf1d82
      m_currentColor = TPixel32::Red;
shun_iwasawa e553fc
    } else if (TPalette *plt = app->getCurrentPalette()->getPalette()) {
bf1d82
      int style               = app->getCurrentLevelStyleIndex();
bf1d82
      TColorStyle *colorStyle = plt->getStyle(style);
bf1d82
      m_currentColor          = colorStyle->getMainColor();
bf1d82
    }
shun_iwasawa e3df22
  }
shun_iwasawa e3df22
bf1d82
  int prevMinCursorThick = m_minCursorThick;
bf1d82
  int prevMaxCursorThick = m_maxCursorThick;
bf1d82
bf1d82
  m_enabledPressure = m_pressure.getValue();
bf1d82
  if (TMyPaintBrushStyle *brushStyle = getBrushStyle()) {
shun_iwasawa e553fc
    double radiusLog = brushStyle->getBrush().getBaseValue(
shun_iwasawa e553fc
                           MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC) +
shun_iwasawa e553fc
                       m_modifierSize.getValue() * log(2.0);
shun_iwasawa e553fc
    double radius    = exp(radiusLog);
shun_iwasawa e553fc
    m_minCursorThick = m_maxCursorThick = (int)round(2.0 * radius);
bf1d82
  } else {
bf1d82
    m_minCursorThick = std::max(m_thickness.getValue().first, 1);
shun_iwasawa e553fc
    m_maxCursorThick =
shun_iwasawa e553fc
        std::max(m_thickness.getValue().second, m_minCursorThick);
shun-iwasawa 76d093
    if (!m_enabledPressure) m_minCursorThick = m_maxCursorThick;
bf1d82
  }
bf1d82
shun-iwasawa 7b497a
  // if this function is called from onEnter(), the clipping rect will not be
shun-iwasawa 7b497a
  // set in order to update whole viewer.
shun-iwasawa 7b497a
  if (prevMinCursorThick == 0 && prevMaxCursorThick == 0) return;
shun-iwasawa 7b497a
shun_iwasawa e553fc
  if (m_minCursorThick != prevMinCursorThick ||
shun_iwasawa e553fc
      m_maxCursorThick != prevMaxCursorThick) {
shun_iwasawa e553fc
    TRectD rect(
shun_iwasawa e553fc
        m_brushPos - TPointD(m_maxCursorThick + 2, m_maxCursorThick + 2),
shun_iwasawa e553fc
        m_brushPos + TPointD(m_maxCursorThick + 2, m_maxCursorThick + 2));
bf1d82
    invalidate(rect);
bf1d82
  }
bf1d82
}
bf1d82
bf1d82
//------------------------------------------------------------------
bf1d82
bf1d82
double FullColorBrushTool::restartBrushTimer() {
shun_iwasawa e553fc
  double dtime = m_brushTimer.nsecsElapsed() * 1e-9;
bf1d82
  m_brushTimer.restart();
bf1d82
  return dtime;
bf1d82
}
bf1d82
bf1d82
//------------------------------------------------------------------
bf1d82
shun_iwasawa e553fc
TMyPaintBrushStyle *FullColorBrushTool::getBrushStyle() {
bf1d82
  if (TTool::Application *app = getApplication())
shun_iwasawa e553fc
    return dynamic_cast<tmypaintbrushstyle *="">(app->getCurrentLevelStyle());</tmypaintbrushstyle>
bf1d82
  return 0;
shun_iwasawa e3df22
}
shun_iwasawa e3df22
bf1d82
//------------------------------------------------------------------
bf1d82
shun_iwasawa e553fc
void FullColorBrushTool::applyClassicToonzBrushSettings(
shun_iwasawa e553fc
    mypaint::Brush &mypaintBrush) {
shun_iwasawa e553fc
  const double precision       = 1e-5;
bf1d82
  const double hardnessOpacity = 0.1;
bf1d82
shun_iwasawa e553fc
  double minThickness = 0.5 * m_thickness.getValue().first;
shun_iwasawa e553fc
  double maxThickness = 0.5 * m_thickness.getValue().second;
shun_iwasawa e553fc
  double minOpacity   = 0.01 * m_opacity.getValue().first;
shun_iwasawa e553fc
  double maxOpacity   = 0.01 * m_opacity.getValue().second;
shun_iwasawa e553fc
  double hardness     = 0.01 * m_hardness.getValue();
bf1d82
shun_iwasawa e553fc
  TPixelD color = PixelConverter<tpixeld>::from(m_currentColor);</tpixeld>
shun_iwasawa e553fc
  double colorH = 0.0;
shun_iwasawa e553fc
  double colorS = 0.0;
shun_iwasawa e553fc
  double colorV = 0.0;
bf1d82
  RGB2HSV(color.r, color.g, color.b, &colorH, &colorS, &colorV);
bf1d82
bf1d82
  // avoid log(0)
shun_iwasawa e553fc
  if (minThickness < precision) minThickness = precision;
shun_iwasawa e553fc
  if (maxThickness < precision) maxThickness = precision;
bf1d82
bf1d82
  // tune hardness opacity for better visual softness
bf1d82
  hardness *= hardness;
shun_iwasawa e553fc
  double opacityAmplifier = 1.0 - hardnessOpacity + hardness * hardnessOpacity;
bf1d82
  minOpacity *= opacityAmplifier;
bf1d82
  maxOpacity *= opacityAmplifier;
bf1d82
bf1d82
  // reset
bf1d82
  mypaintBrush.fromDefaults();
bf1d82
  mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_OPAQUE_MULTIPLY, 1.0);
shun_iwasawa e553fc
  mypaintBrush.setMappingN(MYPAINT_BRUSH_SETTING_OPAQUE_MULTIPLY,
shun_iwasawa e553fc
                           MYPAINT_BRUSH_INPUT_PRESSURE, 0);
shun_iwasawa e553fc
shun_iwasawa e553fc
  mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_HARDNESS,
shun_iwasawa e553fc
                            0.5 * hardness + 0.5);
shun_iwasawa e553fc
  mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_COLOR_H, colorH / 360.0);
shun_iwasawa e553fc
  mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_COLOR_S, colorS);
shun_iwasawa e553fc
  mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_COLOR_V, colorV);
shun_iwasawa e553fc
  mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_DABS_PER_ACTUAL_RADIUS,
shun_iwasawa e553fc
                            5.0 + hardness * 10.0);
bf1d82
  mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_DABS_PER_BASIC_RADIUS, 0.0);
bf1d82
  mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_DABS_PER_SECOND, 0.0);
bf1d82
bf1d82
  // thickness may be dynamic
bf1d82
  if (minThickness + precision >= maxThickness) {
shun_iwasawa e553fc
    mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC,
shun_iwasawa e553fc
                              log(maxThickness));
shun_iwasawa e553fc
    mypaintBrush.setMappingN(MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC,
shun_iwasawa e553fc
                             MYPAINT_BRUSH_INPUT_PRESSURE, 0);
bf1d82
  } else {
shun_iwasawa e553fc
    double minThicknessLog  = log(minThickness);
shun_iwasawa e553fc
    double maxThicknessLog  = log(maxThickness);
shun_iwasawa e553fc
    double baseThicknessLog = 0.5 * (minThicknessLog + maxThicknessLog);
shun_iwasawa e553fc
    mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC,
shun_iwasawa e553fc
                              baseThicknessLog);
shun_iwasawa e553fc
    mypaintBrush.setMappingN(MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC,
shun_iwasawa e553fc
                             MYPAINT_BRUSH_INPUT_PRESSURE, 2);
shun_iwasawa e553fc
    mypaintBrush.setMappingPoint(MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC,
shun_iwasawa e553fc
                                 MYPAINT_BRUSH_INPUT_PRESSURE, 0, 0.0,
shun_iwasawa e553fc
                                 minThicknessLog - baseThicknessLog);
shun_iwasawa e553fc
    mypaintBrush.setMappingPoint(MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC,
shun_iwasawa e553fc
                                 MYPAINT_BRUSH_INPUT_PRESSURE, 1, 1.0,
shun_iwasawa e553fc
                                 maxThicknessLog - baseThicknessLog);
bf1d82
  }
bf1d82
bf1d82
  // opacity may be dynamic
bf1d82
  if (minOpacity + precision >= maxOpacity) {
bf1d82
    mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_OPAQUE, maxOpacity);
shun_iwasawa e553fc
    mypaintBrush.setMappingN(MYPAINT_BRUSH_SETTING_OPAQUE,
shun_iwasawa e553fc
                             MYPAINT_BRUSH_INPUT_PRESSURE, 0);
bf1d82
  } else {
bf1d82
    mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_OPAQUE, minOpacity);
shun_iwasawa e553fc
    mypaintBrush.setMappingN(MYPAINT_BRUSH_SETTING_OPAQUE,
shun_iwasawa e553fc
                             MYPAINT_BRUSH_INPUT_PRESSURE, 2);
shun_iwasawa e553fc
    mypaintBrush.setMappingPoint(MYPAINT_BRUSH_SETTING_OPAQUE,
shun_iwasawa e553fc
                                 MYPAINT_BRUSH_INPUT_PRESSURE, 0, 0.0, 0.0);
shun_iwasawa e553fc
    mypaintBrush.setMappingPoint(MYPAINT_BRUSH_SETTING_OPAQUE,
shun_iwasawa e553fc
                                 MYPAINT_BRUSH_INPUT_PRESSURE, 1, 1.0,
shun_iwasawa e553fc
                                 maxOpacity - minOpacity);
bf1d82
  }
manongjohn 963976
manongjohn 963976
  if (m_modifierLockAlpha.getValue()) {
manongjohn 963976
    mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_LOCK_ALPHA, 1.0);
manongjohn 963976
  }
bf1d82
}
bf1d82
bf1d82
void FullColorBrushTool::applyToonzBrushSettings(mypaint::Brush &mypaintBrush) {
bf1d82
  TMyPaintBrushStyle *mypaintStyle = getBrushStyle();
bf1d82
bf1d82
  if (mypaintStyle) {
bf1d82
    const double precision = 1e-5;
bf1d82
shun_iwasawa e553fc
    double modifierSize    = m_modifierSize.getValue() * log(2.0);
shun_iwasawa e553fc
    double modifierOpacity = 0.01 * m_modifierOpacity.getValue();
shun_iwasawa 9a4581
    bool modifierEraser    = m_modifierEraser.getValue();
shun_iwasawa 9a4581
    bool modifierLockAlpha = m_modifierLockAlpha.getValue();
bf1d82
shun_iwasawa e553fc
    TPixelD color = PixelConverter<tpixeld>::from(m_currentColor);</tpixeld>
shun_iwasawa e553fc
    double colorH = 0.0;
shun_iwasawa e553fc
    double colorS = 0.0;
shun_iwasawa e553fc
    double colorV = 0.0;
bf1d82
    RGB2HSV(color.r, color.g, color.b, &colorH, &colorS, &colorV);
bf1d82
bf1d82
    mypaintBrush.fromBrush(mypaintStyle->getBrush());
bf1d82
shun_iwasawa e553fc
    float baseSize =
shun_iwasawa e553fc
        mypaintBrush.getBaseValue(MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC);
bf1d82
    float baseOpacity = mypaintBrush.getBaseValue(MYPAINT_BRUSH_SETTING_OPAQUE);
bf1d82
shun_iwasawa e553fc
    mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC,
shun_iwasawa e553fc
                              baseSize + modifierSize);
shun_iwasawa e553fc
    mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_OPAQUE,
shun_iwasawa e553fc
                              baseOpacity * modifierOpacity);
shun_iwasawa e553fc
    mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_COLOR_H, colorH / 360.0);
shun_iwasawa e553fc
    mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_COLOR_S, colorS);
shun_iwasawa e553fc
    mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_COLOR_V, colorV);
572ed1
572ed1
    if (modifierEraser) {
572ed1
      mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_ERASER, 1.0);
572ed1
      mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_LOCK_ALPHA, 0.0);
572ed1
    } else if (modifierLockAlpha) {
572ed1
      // lock-alpha already disables eraser
572ed1
      mypaintBrush.setBaseValue(MYPAINT_BRUSH_SETTING_LOCK_ALPHA, 1.0);
572ed1
    }
bf1d82
  } else {
bf1d82
    applyClassicToonzBrushSettings(mypaintBrush);
bf1d82
  }
bf1d82
}
bf1d82
Toshihiro Shimizu 890ddd
//==========================================================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
FullColorBrushToolNotifier::FullColorBrushToolNotifier(FullColorBrushTool *tool)
Shinya Kitaoka 120a6e
    : m_tool(tool) {
bf1d82
  if (TTool::Application *app = m_tool->getApplication()) {
bf1d82
    if (TXshLevelHandle *levelHandle = app->getCurrentLevel()) {
bf1d82
      bool ret = connect(levelHandle, SIGNAL(xshCanvasSizeChanged()), this,
bf1d82
                         SLOT(onCanvasSizeChanged()));
bf1d82
      assert(ret);
bf1d82
    }
bf1d82
    if (TPaletteHandle *paletteHandle = app->getCurrentPalette()) {
bf1d82
      bool ret;
shun_iwasawa e553fc
      ret = connect(paletteHandle, SIGNAL(colorStyleChanged(bool)), this,
bf1d82
                    SLOT(onColorStyleChanged()));
bf1d82
      assert(ret);
bf1d82
      ret = connect(paletteHandle, SIGNAL(colorStyleSwitched()), this,
bf1d82
                    SLOT(onColorStyleChanged()));
bf1d82
      assert(ret);
bf1d82
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==========================================================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
FullColorBrushTool fullColorPencil("T_Brush");