diff --git a/toonz/sources/include/tools/inputmanager.h b/toonz/sources/include/tools/inputmanager.h index 5cbe005..dad6a50 100644 --- a/toonz/sources/include/tools/inputmanager.h +++ b/toonz/sources/include/tools/inputmanager.h @@ -40,7 +40,6 @@ class TInputModifier; class TInputManager; typedef TSmartPointerT<TInputModifier> TInputModifierP; -typedef TSmartPointerT<TInputManager> TInputManagerP; //=================================================================== @@ -69,6 +68,9 @@ public: inline Holder& operator= (const Holder &other) { set(other.m_savePoint, other.m_lock); return *this; } + inline operator bool () const + { return assigned(); } + inline void set(TInputSavePoint *savePoint, bool lock) { if (m_savePoint != savePoint) { if (m_savePoint) { @@ -83,8 +85,10 @@ public: } } else if (m_lock != lock) { - if (lock) m_savePoint->lock(); - else m_savePoint->unlock(); + if (m_savePoint) { + if (lock) m_savePoint->lock(); + else m_savePoint->unlock(); + } m_lock = lock; } } @@ -98,6 +102,8 @@ public: inline TInputSavePoint* savePoint() const { return m_savePoint; } + inline bool assigned() const + { return savePoint(); } inline bool locked() const { return m_savePoint && m_lock; } inline bool available() const @@ -235,7 +241,7 @@ public: // TInputManager definition //***************************************************************************************** -class TInputManager: public TSmartObject { +class TInputManager { public: class TrackHandler: public TTrackHandler { public: @@ -246,6 +252,7 @@ public: }; private: + TTimerTicks m_lastTicks; TInputHandler *m_handler; TInputModifier::List m_modifiers; std::vector<TTrackList> m_tracks; @@ -264,6 +271,11 @@ public: TInputManager(); private: + inline TTimerTicks fixTicks(TTimerTicks ticks) { + if (ticks <= m_lastTicks) ticks = m_lastTicks + 1; + return m_lastTicks = ticks; + } + void paintRollbackTo(int saveIndex, TTrackList &subTracks); void paintApply(int count, TTrackList &subTracks); void paintTracks(); @@ -271,7 +283,7 @@ private: int trackCompare( const TTrack &track, TInputState::DeviceId deviceId, - TInputState::TouchId touchId ); + TInputState::TouchId touchId ) const; const TTrackP& createTrack( int index, TInputState::DeviceId deviceId, diff --git a/toonz/sources/include/tools/inputstate.h b/toonz/sources/include/tools/inputstate.h index faab530..628f906 100644 --- a/toonz/sources/include/tools/inputstate.h +++ b/toonz/sources/include/tools/inputstate.h @@ -18,6 +18,7 @@ // std includes #include <map> #include <vector> +#include <iostream> #undef DVAPI @@ -199,6 +200,10 @@ public: { return ButtonHistory::Holder(buttonHistory(deviceId), ticks, timeOffset); } inline ButtonHistory::Holder buttonHistoryHolder(DeviceId deviceId) { return buttonHistoryHolder(deviceId, m_ticks); } + + void print(std::ostream &stream, const std::string &tab = std::string()) const; + inline void print(const std::string &tab = std::string()) const + { print(std::cout, tab); } }; diff --git a/toonz/sources/include/tools/keyhistory.h b/toonz/sources/include/tools/keyhistory.h index 6bf4d27..0c0e5fe 100644 --- a/toonz/sources/include/tools/keyhistory.h +++ b/toonz/sources/include/tools/keyhistory.h @@ -76,8 +76,9 @@ private: previous(previous), ticks(ticks), value(value) { } Pointer makeChainWithout(const Pointer &state) { - return state == this || !previous ? previous - : Pointer(new TKeyStateT(previous->makeChainWithout(state), ticks, value)); + return state == this ? previous + : previous ? Pointer(new TKeyStateT(previous->makeChainWithout(state), ticks, value)) + : this; } public: @@ -93,18 +94,18 @@ public: Pointer change(bool press, const Type &value, TTimerTicks ticks) { if (value == none) return Pointer(this); + + Pointer p = find(value); + if (press == bool(p)) + return Pointer(this); + if (ticks <= this->ticks) ticks = this->ticks + 1; - Pointer p = find(value); - if (press) { - if (p) return Pointer(this); + if (press) return Pointer(new TKeyStateT((isEmpty() ? Pointer() : Pointer(this)), ticks, value)); - } - - if (!p) return Pointer(this); Pointer chain = makeChainWithout(p); - return chain ? chain : Pointer(new TKeyStateT()); + return chain ? chain : Pointer(new TKeyStateT(Pointer(), ticks, none)); } bool isEmpty() @@ -138,6 +139,8 @@ public: typedef TKeyStateT<Type> State; typedef typename TKeyStateT<Type>::Pointer StatePointer; typedef typename TKeyStateT<Type>::Holder StateHolder; + typedef std::map<TTimerTicks, StatePointer> StateMap; + typedef std::multiset<TTimerTicks> LockSet; class Holder { private: @@ -162,11 +165,13 @@ public: { set(other); return *this; } void set(const Pointer &history, TTimerTicks ticks, double timeOffset = 0.0) { - if (m_history) m_history->releaseTicks(m_heldTicks); + TTimerTicks prevHeldTicks = m_heldTicks; + Pointer prevHistory = m_history; m_history = history; m_ticks = ticks; m_timeOffset = timeOffset; m_heldTicks = (m_history ? m_history->holdTicks(m_ticks) : 0); + if (prevHistory) prevHistory->releaseTicks(prevHeldTicks); } void set(const Holder &other) { set(other.history(), other.ticks(), other.timeOffset()); } @@ -193,15 +198,15 @@ public: }; private: - std::map<TTimerTicks, StatePointer> m_states; - std::multiset<TTimerTicks> m_locks; + StateMap m_states; + LockSet m_locks; void autoRemove() { - TTimerTicks ticks = m_locks.empty() - ? m_states.rbegin()->first - : *m_locks.begin(); + TTimerTicks ticks = m_states.rbegin()->first; + if (!m_locks.empty()) + ticks = std::min(ticks, *m_locks.begin()); while(true) { - typename std::map<TTimerTicks, StatePointer>::iterator i = m_states.begin(); + typename StateMap::iterator i = m_states.begin(); ++i; if (i == m_states.end() || (!i->second->isEmpty() && i->first >= ticks)) break; m_states.erase(i); @@ -210,11 +215,15 @@ private: TTimerTicks holdTicks(TTimerTicks ticks) { return *m_locks.insert(std::max(ticks, m_states.begin()->first)); } - void releaseTicks(TTimerTicks heldTicks) - { m_locks.erase(heldTicks); autoRemove(); } + void releaseTicks(TTimerTicks heldTicks) { + typename LockSet::iterator i = m_locks.find(heldTicks); + if (i == m_locks.end()) return; + m_locks.erase(i); + autoRemove(); + } StatePointer get(TTimerTicks ticks) { - typename std::map<TTimerTicks, StatePointer>::iterator i = m_states.upper_bound(ticks); + typename StateMap::iterator i = m_states.upper_bound(ticks); return i == m_states.begin() ? i->second : (--i)->second; } @@ -238,6 +247,11 @@ public: StatePointer released(Type value, TTimerTicks ticks) { return change(false, value, ticks); } + + inline const StateMap& getStates() const + { return m_states; } + inline const LockSet& getLocks() const + { return m_locks; } }; diff --git a/toonz/sources/include/tools/modifiers/modifiersegmentation.h b/toonz/sources/include/tools/modifiers/modifiersegmentation.h new file mode 100644 index 0000000..b6466d0 --- /dev/null +++ b/toonz/sources/include/tools/modifiers/modifiersegmentation.h @@ -0,0 +1,45 @@ +#pragma once + +#ifndef MODIFIERSEGMENTATION_INCLUDED +#define MODIFIERSEGMENTATION_INCLUDED + +// TnzTools includes +#include <tools/inputmanager.h> + + +#undef DVAPI +#undef DVVAR +#ifdef TNZTOOLS_EXPORTS +#define DVAPI DV_EXPORT_API +#define DVVAR DV_EXPORT_VAR +#else +#define DVAPI DV_IMPORT_API +#define DVVAR DV_IMPORT_VAR +#endif + + +//=================================================================== + +//***************************************************************************************** +// TModifierSegmentation definition +//***************************************************************************************** + +class TModifierSegmentation: public TInputModifier { +public: + const double precision; + const double precisionSqr; + +private: + void addSegments(TTrack &track, const TTrackPoint &p0, const TTrackPoint &p1, int level = 0); + +public: + TModifierSegmentation(double precision = 1.0); + + void modifyTrack( + const TTrackP &track, + const TInputSavePoint::Holder &savePoint, + TTrackList &outTracks ) override; +}; + + +#endif diff --git a/toonz/sources/include/tools/modifiers/modifiertangents.h b/toonz/sources/include/tools/modifiers/modifiertangents.h new file mode 100644 index 0000000..12e4059 --- /dev/null +++ b/toonz/sources/include/tools/modifiers/modifiertangents.h @@ -0,0 +1,46 @@ +#pragma once + +#ifndef MODIFIERTANGENTS_INCLUDED +#define MODIFIERTANGENTS_INCLUDED + +// TnzTools includes +#include <tools/inputmanager.h> + + +#undef DVAPI +#undef DVVAR +#ifdef TNZTOOLS_EXPORTS +#define DVAPI DV_EXPORT_API +#define DVVAR DV_EXPORT_VAR +#else +#define DVAPI DV_IMPORT_API +#define DVVAR DV_IMPORT_VAR +#endif + + +//=================================================================== + +//***************************************************************************************** +// TModifierTangents definition +//***************************************************************************************** + +class TModifierTangents: public TInputModifier { +public: + class Modifier: public TTrackModifier { + public: + explicit Modifier(TTrackHandler &handler): + TTrackModifier(handler) { } + + TInputSavePoint::Holder savePoint; + TTrackTangentList tangents; + + TTrackPoint calcPoint(double originalIndex) override; + }; + + void modifyTrack( + const TTrackP &track, + const TInputSavePoint::Holder &savePoint, + TTrackList &outTracks ) override; +}; + +#endif diff --git a/toonz/sources/include/tools/modifiers/modifiertest.h b/toonz/sources/include/tools/modifiers/modifiertest.h new file mode 100644 index 0000000..d21c813 --- /dev/null +++ b/toonz/sources/include/tools/modifiers/modifiertest.h @@ -0,0 +1,58 @@ +#pragma once + +#ifndef MODIFIERTEST_INCLUDED +#define MODIFIERTEST_INCLUDED + +// TnzTools includes +#include <tools/inputmanager.h> + + +#undef DVAPI +#undef DVVAR +#ifdef TNZTOOLS_EXPORTS +#define DVAPI DV_EXPORT_API +#define DVVAR DV_EXPORT_VAR +#else +#define DVAPI DV_IMPORT_API +#define DVVAR DV_IMPORT_VAR +#endif + + +//=================================================================== + +//***************************************************************************************** +// TModifierTest definition +//***************************************************************************************** + +class TModifierTest: public TInputModifier { +public: + class Handler: public TTrackHandler { + public: + std::vector<double> angles; + Handler(TTrack &original): TTrackHandler(original) { } + }; + + class Modifier: public TTrackModifier { + public: + double angle; + double radius; + double speed; + + Modifier(TTrackHandler &handler, double angle, double radius, double speed = 0.25); + TTrackPoint calcPoint(double originalIndex) override; + }; + +public: + const int count; + const double radius; + + TModifierTest(); + + void modifyTrack( + const TTrackP &track, + const TInputSavePoint::Holder &savePoint, + TTrackList &outTracks ) override; +}; + + +#endif diff --git a/toonz/sources/include/tools/modifiertest.h b/toonz/sources/include/tools/modifiertest.h deleted file mode 100644 index b328e0f..0000000 --- a/toonz/sources/include/tools/modifiertest.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#ifndef MODIFIERTEST_INCLUDED -#define MODIFIERTEST_INCLUDED - -// TnzTools includes -#include <tools/inputmanager.h> - -// std includes -#include <cmath> - - -#undef DVAPI -#undef DVVAR -#ifdef TNZTOOLS_EXPORTS -#define DVAPI DV_EXPORT_API -#define DVVAR DV_EXPORT_VAR -#else -#define DVAPI DV_IMPORT_API -#define DVVAR DV_IMPORT_VAR -#endif - - -//=================================================================== - -//***************************************************************************************** -// TModifierTest definition -//***************************************************************************************** - -class TModifierTest: public TInputModifier { -public: - class Handler: public TTrackHandler { - public: - std::vector<double> angles; - Handler(TTrack &original): TTrackHandler(original) { } - }; - - class Modifier: public TTrackModifier { - public: - double angle; - double radius; - double speed; - - Modifier(TTrackHandler &handler, double angle, double radius, double speed = 0.25); - TTrackPoint calcPoint(double originalIndex); - }; - -public: - int count; - double radius; - - explicit TModifierTest(); - - void modifyTrack( - const TTrackP &track, - const TInputSavePoint::Holder &savePoint, - TTrackList &outTracks ) override; -}; - - -#endif diff --git a/toonz/sources/include/tools/track.h b/toonz/sources/include/tools/track.h index 0efccce..16331f9 100644 --- a/toonz/sources/include/tools/track.h +++ b/toonz/sources/include/tools/track.h @@ -35,6 +35,7 @@ class TTrack; class TTrackPoint; +class TTrackTangent; class TTrackHandler; class TTrackModifier; @@ -43,6 +44,7 @@ typedef TSmartPointerT<TTrackHandler> TTrackHandlerP; typedef TSmartPointerT<TTrackModifier> TTrackModifierP; typedef std::vector<TTrackPoint> TTrackPointList; +typedef std::vector<TTrackTangent> TTrackTangentList; typedef std::vector<TTrackP> TTrackList; //=================================================================== @@ -85,6 +87,28 @@ public: //***************************************************************************************** +// TTrackTangent definition +//***************************************************************************************** + +class TTrackTangent { +public: + TPointD position; + double pressure; + TPointD tilt; + + inline explicit TTrackTangent( + const TPointD &position = TPointD(), + double pressure = 0.0, + const TPointD &tilt = TPointD() + ): + position(position), + pressure(pressure), + tilt(tilt) + { } +}; + + +//***************************************************************************************** // TTrackHandler definition //***************************************************************************************** @@ -216,10 +240,14 @@ public: { return point(size() - pointsAdded); } inline TInputState::KeyState::Holder getKeyState(double time) const { return keyHistory.get(time); } + inline TInputState::KeyState::Holder getKeyState(const TTrackPoint &point) const + { return getKeyState(timeOffset() + point.time); } inline TInputState::KeyState::Holder getCurrentKeyState() const { return getKeyState(current().time); } inline TInputState::ButtonState::Holder getButtonState(double time) const { return buttonHistory.get(time); } + inline TInputState::ButtonState::Holder getButtonState(const TTrackPoint &point) const + { return getButtonState(timeOffset() + point.time); } inline TInputState::ButtonState::Holder getCurrentButtonState() const { return getButtonState(current().time); } @@ -287,6 +315,16 @@ public: static inline T interpolationLinear(const T &p0, const T &p1, double l) { return p0*(1.0 - l) + p1*l; } + template<typename T> + static T interpolationSpline(const T &p0, const T &p1, const T &t0, const T &t1, double l) { + double ll = l*l; + double lll = ll*l; + return p0*( 2.0*lll - 3.0*ll + 1.0) + + p1*(-2.0*lll + 3.0*ll ) + + t0*( lll - 2.0*ll + l ) + + t1*( lll - 1.0*ll ); + } + static inline TTrackPoint interpolationLinear(const TTrackPoint &p0, const TTrackPoint &p1, double l) { if (l <= epsilon) return p0; if (l >= 1.0 - epsilon) return p1; @@ -298,6 +336,24 @@ public: interpolationLinear(p0.time , p1.time , l), interpolationLinear(p0.length , p1.length , l) ); } + + static inline TTrackPoint interpolationSpline( + const TTrackPoint &p0, + const TTrackPoint &p1, + const TTrackTangent &t0, + const TTrackTangent &t1, + double l ) + { + if (l <= epsilon) return p0; + if (l >= 1.0 - epsilon) return p1; + return TTrackPoint( + interpolationSpline(p0.position , p1.position , t0.position , t1.position , l), + interpolationSpline(p0.pressure , p1.pressure , t0.pressure , t1.pressure , l), + interpolationSpline(p0.tilt , p1.tilt , t0.tilt , t1.tilt , l), + interpolationLinear(p0.originalIndex , p1.originalIndex , l), + interpolationLinear(p0.time , p1.time , l), + interpolationLinear(p0.length , p1.length , l) ); + } }; #endif diff --git a/toonz/sources/tnztools/CMakeLists.txt b/toonz/sources/tnztools/CMakeLists.txt index c426de8..b1c8939 100644 --- a/toonz/sources/tnztools/CMakeLists.txt +++ b/toonz/sources/tnztools/CMakeLists.txt @@ -48,7 +48,9 @@ set(HEADERS ../include/tools/inputstate.h ../include/tools/track.h ../include/tools/inputmanager.h - ../include/tools/modifiertest.h + ../include/tools/modifiers/modifiertest.h + ../include/tools/modifiers/modifiertangents.h + ../include/tools/modifiers/modifiersegmentation.h ) set(SOURCES @@ -117,6 +119,8 @@ set(SOURCES track.cpp inputmanager.cpp modifiertest.cpp + modifiertangents.cpp + modifiersegmentation.cpp ) set(RESOURCES tnztools.qrc) diff --git a/toonz/sources/tnztools/fullcolorbrushtool.cpp b/toonz/sources/tnztools/fullcolorbrushtool.cpp index 475241e..9f8a3b3 100644 --- a/toonz/sources/tnztools/fullcolorbrushtool.cpp +++ b/toonz/sources/tnztools/fullcolorbrushtool.cpp @@ -123,9 +123,9 @@ FullColorBrushTool::FullColorBrushTool(std::string name) , m_modifierEraser("ModifierEraser", false) , m_modifierLockAlpha("Lock Alpha", false) , m_preset("Preset:") + , m_enabledPressure(false) , m_minCursorThick(0) , m_maxCursorThick(0) - , m_enabledPressure(false) , m_toonz_brush(0) , m_tileSet(0) , m_tileSaver(0) @@ -134,6 +134,11 @@ FullColorBrushTool::FullColorBrushTool(std::string name) , m_firstTime(true) { bind(TTool::RasterImage | TTool::EmptyTarget); + m_inputmanager.setHandler(this); + m_modifierTest = new TModifierTest(); + m_modifierTangents = new TModifierTangents(); + m_modifierSegmentation = new TModifierSegmentation(); + m_thickness.setNonLinearSlider(); m_prop.bind(m_thickness); @@ -219,7 +224,7 @@ void FullColorBrushTool::onActivate() { //-------------------------------------------------------------------------------------------------- void FullColorBrushTool::onDeactivate() { - if (m_mousePressed) leftButtonUp(m_mousePos, m_mouseEvent); + m_inputmanager.finishTracks(); m_workRaster = TRaster32P(); m_backUpRas = TRasterP(); } @@ -288,6 +293,11 @@ bool FullColorBrushTool::askWrite(const TRect &rect) { //-------------------------------------------------------------------------------------------------- bool FullColorBrushTool::preLeftButtonDown() { + m_inputmanager.clearModifiers(); + m_inputmanager.addModifier( TInputModifierP(m_modifierTangents.getPointer()) ); + m_inputmanager.addModifier( TInputModifierP(m_modifierSegmentation.getPointer()) ); + m_inputmanager.addModifier( TInputModifierP(m_modifierTest.getPointer()) ); + touchImage(); if (m_isFrameCreated) { @@ -303,12 +313,50 @@ bool FullColorBrushTool::preLeftButtonDown() { //--------------------------------------------------------------------------------------------------- -void FullColorBrushTool::leftButtonDown(const TPointD &pos, - const TMouseEvent &e) { +void FullColorBrushTool::handleMouseEvent(MouseEventType type, const TPointD &pos, const TMouseEvent &e) { + 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 (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); + + 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(); + } +} + +//--------------------------------------------------------------------------------------------------- + +void FullColorBrushTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) + { handleMouseEvent(ME_DOWN, pos, e); } +void FullColorBrushTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &e) + { handleMouseEvent(ME_DRAG, pos, e); } +void FullColorBrushTool::leftButtonUp(const TPointD &pos, const TMouseEvent &e) + { handleMouseEvent(ME_UP, pos, e); } +void FullColorBrushTool::mouseMove(const TPointD &pos, const TMouseEvent &e) + { handleMouseEvent(ME_MOVE, pos, e); } + +//--------------------------------------------------------------------------------------------------- + +void FullColorBrushTool::inputLeftButtonDown( + const TTrackPoint &point, const TTrack &track ) +{ + const TPointD &pos = point.position; TPointD previousBrushPos = m_brushPos; m_brushPos = m_mousePos = pos; m_mousePressed = true; - m_mouseEvent = e; Viewer *viewer = getViewer(); if (!viewer) return; @@ -318,7 +366,8 @@ void FullColorBrushTool::leftButtonDown(const TPointD &pos, if (!ri) return; // Modifier to do straight line - if (e.isShiftPressed() || e.isCtrlPressed()) { + TInputState::KeyState::Holder keys = track.getKeyState(point); + if (keys.isPressed(TKey::shift) || keys.isPressed(TKey::control)) { m_isStraight = true; m_firstPoint = pos; m_lastPoint = pos; @@ -335,26 +384,24 @@ void FullColorBrushTool::leftButtonDown(const TPointD &pos, m_workRaster->lock(); TPointD rasCenter = ras->getCenterD(); - TPointD point(pos + rasCenter); + TPointD pt(pos + rasCenter); - double pressure; - if (getApplication()->getCurrentLevelStyle()->getTagId() == - 4001) // mypaint brush case - pressure = m_enabledPressure && e.isTablet() ? e.m_pressure : 0.5; - else - pressure = m_enabledPressure ? e.m_pressure : 1.0; + double defPressure = 1.0; + if (getApplication()->getCurrentLevelStyle()->getTagId() == 4001) // mypaint brush case + defPressure = 0.5; + double pressure = m_enabledPressure && track.hasPressure ? point.pressure : defPressure; m_tileSet = new TTileSetFullColor(ras->getSize()); m_tileSaver = new TTileSaverFullColor(ras, m_tileSet); mypaint::Brush mypaintBrush; applyToonzBrushSettings(mypaintBrush); - m_toonz_brush = new MyPaintToonzBrush(m_workRaster, *this, mypaintBrush); + m_toonz_brush = new MyPaintToonzBrush(m_workRaster, *this, mypaintBrush, false); m_strokeRect.empty(); m_strokeSegmentRect.empty(); m_toonz_brush->beginStroke(); - m_toonz_brush->strokeTo(point, pressure, restartBrushTimer()); + m_toonz_brush->strokeTo(pt, pressure, restartBrushTimer()); TRect updateRect = m_strokeSegmentRect * ras->getBounds(); if (!updateRect.isEmpty()) ras->extract(updateRect)->copy(m_workRaster->extract(updateRect)); @@ -369,14 +416,16 @@ void FullColorBrushTool::leftButtonDown(const TPointD &pos, //------------------------------------------------------------------------------------------------------------- -void FullColorBrushTool::leftButtonDrag(const TPointD &pos, - const TMouseEvent &e) { +void FullColorBrushTool::inputLeftButtonDrag( + const TTrackPoint &point, const TTrack &track ) +{ + const TPointD &pos = point.position; TRectD invalidateRect; + TPointD previousLastPoint = m_lastPoint; m_lastPoint = pos; TPointD previousBrushPos = m_brushPos; m_brushPos = m_mousePos = pos; - m_mouseEvent = e; TRasterImageP ri = (TRasterImageP)getImage(true); if (!ri) return; @@ -384,31 +433,23 @@ void FullColorBrushTool::leftButtonDrag(const TPointD &pos, TRasterP ras = ri->getRaster(); TPointD rasCenter = ras->getCenterD(); - TPointD point(pos + rasCenter); - double pressure; - if (getApplication()->getCurrentLevelStyle()->getTagId() == - 4001) // mypaint brush case - pressure = m_enabledPressure && e.isTablet() ? e.m_pressure : 0.5; - else - pressure = m_enabledPressure ? e.m_pressure : 1.0; + TPointD pt(pos + rasCenter); + + double defPressure = 1.0; + if (getApplication()->getCurrentLevelStyle()->getTagId() == 4001) // mypaint brush case + defPressure = 0.5; + double pressure = m_enabledPressure && track.hasPressure ? point.pressure : defPressure; if (m_maxPressure < pressure) m_maxPressure = pressure; if (m_isStraight) { - invalidateRect = TRectD(m_firstPoint, m_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_lastPoint.x - m_firstPoint.x; - if (denominator == 0) denominator = 0.001; - double slope = ((m_lastPoint.y - m_firstPoint.y) / denominator); - double angle = std::atan(slope) * (180 / 3.14159); - if (abs(angle) > 67.5) + if (track.getKeyState(point).isPressed(TKey::control)) { + TPointD dist = m_lastPoint - m_firstPoint; + double angle = fabs(atan(dist)) * (180 / 3.14159); + if (angle > 90) angle = 180 - angle; + if (angle > 90 - 22.5) m_lastPoint.x = m_firstPoint.x; - else if (abs(angle) < 22.5) + else if (angle < 22.5) m_lastPoint.y = m_firstPoint.y; else { double xDistance = m_lastPoint.x - m_firstPoint.x; @@ -426,14 +467,18 @@ void FullColorBrushTool::leftButtonDrag(const TPointD &pos, } } } - m_mousePos = pos; - m_brushPos = pos; + double cursorSize = m_maxCursorThick/2 + 2; + TPointD cursorSize2d(cursorSize, cursorSize); + invalidateRect = TRectD(m_firstPoint, previousLastPoint).enlarge(2); + invalidateRect += TRectD(previousBrushPos - cursorSize2d, previousBrushPos + cursorSize2d); + invalidateRect += TRectD(m_brushPos - cursorSize2d, m_brushPos + cursorSize2d); + invalidateRect += TRectD(m_firstPoint, m_lastPoint).enlarge(2); invalidate(invalidateRect); return; } m_strokeSegmentRect.empty(); - m_toonz_brush->strokeTo(point, pressure, restartBrushTimer()); + m_toonz_brush->strokeTo(pt, pressure, restartBrushTimer()); TRect updateRect = m_strokeSegmentRect * ras->getBounds(); if (!updateRect.isEmpty()) ras->extract(updateRect)->copy(m_workRaster->extract(updateRect)); @@ -448,8 +493,10 @@ void FullColorBrushTool::leftButtonDrag(const TPointD &pos, //--------------------------------------------------------------------------------------------------------------- -void FullColorBrushTool::leftButtonUp(const TPointD &pos, - const TMouseEvent &e) { +void FullColorBrushTool::inputLeftButtonUp( + const TTrackPoint &point, const TTrack &track ) +{ + const TPointD &pos = point.position; TPointD previousBrushPos = m_brushPos; m_brushPos = m_mousePos = pos; @@ -460,24 +507,22 @@ void FullColorBrushTool::leftButtonUp(const TPointD &pos, TRasterP ras = ri->getRaster(); TPointD rasCenter = ras->getCenterD(); - TPointD point; + TPointD pt; if (m_isStraight) - point = TPointD(m_lastPoint + rasCenter); - else - point = TPointD(pos + rasCenter); - double pressure; - if (getApplication()->getCurrentLevelStyle()->getTagId() == - 4001) // mypaint brush case - pressure = m_enabledPressure && e.isTablet() ? e.m_pressure : 0.5; + pt = TPointD(m_lastPoint + rasCenter); else - pressure = m_enabledPressure ? e.m_pressure : 1.0; + pt = TPointD(pos + rasCenter); - if (m_isStraight && m_maxPressure > 0.0) { + double defPressure = 1.0; + if (getApplication()->getCurrentLevelStyle()->getTagId() == 4001) // mypaint brush case + defPressure = 0.5; + double pressure = m_enabledPressure && track.hasPressure ? point.pressure : defPressure; + + if (m_isStraight && m_maxPressure > 0.0) pressure = m_maxPressure; - } m_strokeSegmentRect.empty(); - m_toonz_brush->strokeTo(point, pressure, restartBrushTimer()); + m_toonz_brush->strokeTo(pt, pressure, restartBrushTimer()); m_toonz_brush->endStroke(); TRect updateRect = m_strokeSegmentRect * ras->getBounds(); if (!updateRect.isEmpty()) @@ -519,7 +564,9 @@ void FullColorBrushTool::leftButtonUp(const TPointD &pos, //--------------------------------------------------------------------------------------------------------------- -void FullColorBrushTool::mouseMove(const TPointD &pos, const TMouseEvent &e) { +void FullColorBrushTool::inputMouseMove( + const TPointD &position, const TInputState &state ) +{ struct Locals { FullColorBrushTool *m_this; @@ -555,26 +602,18 @@ void FullColorBrushTool::mouseMove(const TPointD &pos, const TMouseEvent &e) { setValue(prop, value); } - } 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(m_thickness, int(add)); - //} else - if (e.isCtrlPressed() && e.isAltPressed()) { - const TPointD &diff = pos - m_mousePos; + if (state.isKeyPressed(TKey::control) && state.isKeyPressed(TKey::alt)) { + const TPointD &diff = position - m_mousePos; double max = diff.x / 2; double min = diff.y / 2; - locals.addMinMaxSeparate(m_thickness, int(min), int(max)); } else { - m_brushPos = pos; + m_brushPos = position; } - m_mousePos = pos; + m_mousePos = position; invalidate(); } diff --git a/toonz/sources/tnztools/fullcolorbrushtool.h b/toonz/sources/tnztools/fullcolorbrushtool.h index 23f5b58..6f2b38a 100644 --- a/toonz/sources/tnztools/fullcolorbrushtool.h +++ b/toonz/sources/tnztools/fullcolorbrushtool.h @@ -5,6 +5,11 @@ #include <ctime> +#include <tools/inputmanager.h> +#include <tools/modifiers/modifiertest.h> +#include <tools/modifiers/modifiertangents.h> +#include <tools/modifiers/modifiersegmentation.h> + #include "toonzrasterbrushtool.h" #include "mypainttoonzbrush.h" #include "toonz/mypaintbrushstyle.h" @@ -28,7 +33,7 @@ class Brush; // FullColor Brush Tool declaration //************************************************************************ -class FullColorBrushTool final : public TTool, public RasterController { +class FullColorBrushTool final : public TTool, public RasterController, public TInputHandler { Q_DECLARE_TR_FUNCTIONS(FullColorBrushTool) void updateCurrentStyle(); @@ -57,6 +62,11 @@ public: void leftButtonUp(const TPointD &pos, const TMouseEvent &e) override; void mouseMove(const TPointD &pos, const TMouseEvent &e) override; + void inputLeftButtonDown(const TTrackPoint &point, const TTrack &track) override; + void inputLeftButtonDrag(const TTrackPoint &point, const TTrack &track) override; + void inputLeftButtonUp(const TTrackPoint &point, const TTrack &track) override; + void inputMouseMove(const TPointD &position, const TInputState &state) override; + void draw() override; void onEnter() override; @@ -83,7 +93,16 @@ public: TMyPaintBrushStyle *getBrushStyle(); +private: + enum MouseEventType { ME_DOWN, ME_DRAG, ME_UP, ME_MOVE }; + void handleMouseEvent(MouseEventType type, const TPointD &pos, const TMouseEvent &e); + protected: + TInputManager m_inputmanager; + TSmartPointerT<TModifierTest> m_modifierTest; + TSmartPointerT<TModifierTangents> m_modifierTangents; + TSmartPointerT<TModifierSegmentation> m_modifierSegmentation; + TPropertyGroup m_prop; TIntPairProperty m_thickness; @@ -121,7 +140,6 @@ protected: bool m_presetsLoaded; bool m_firstTime; bool m_mousePressed = false; - TMouseEvent m_mouseEvent; bool m_isStraight = false; TPointD m_firstPoint; diff --git a/toonz/sources/tnztools/inputmanager.cpp b/toonz/sources/tnztools/inputmanager.cpp index 61f7b2a..1f3aa55 100644 --- a/toonz/sources/tnztools/inputmanager.cpp +++ b/toonz/sources/tnztools/inputmanager.cpp @@ -116,7 +116,7 @@ TInputHandler::inputKeyEvent( QKeyEvent *event, const TInputManager &manager ) { - return press && inputKeyDown(event); + return press && event && inputKeyDown(event); } @@ -185,6 +185,7 @@ TInputHandler::inputPaintTracks(const TTrackList &tracks) { TInputManager::TInputManager(): + m_lastTicks(TToolTimer::ticks()), m_handler(), m_tracks(1), m_hovers(1), @@ -338,7 +339,7 @@ int TInputManager::trackCompare( const TTrack &track, TInputState::DeviceId deviceId, - TInputState::TouchId touchId ) + TInputState::TouchId touchId ) const { if (track.deviceId < deviceId) return -1; if (deviceId < track.deviceId) return 1; @@ -430,7 +431,7 @@ TInputManager::touchTracks(bool finish) { for(TTrackList::const_iterator i = m_tracks.front().begin(); i != m_tracks.front().end(); ++i) { if (!(*i)->finished() && (*i)->size() > 0) { const TTrackPoint &p = (*i)->back(); - addTrackPoint(*i, p.position, p.pressure, p.tilt, p.time, finish); + addTrackPoint(*i, p.position, p.pressure, p.tilt, fixTicks(m_lastTicks)*TToolTimer::step, finish); } } } @@ -481,9 +482,8 @@ TInputManager::reset() { void TInputManager::setHandler(TInputHandler *handler) { - if (m_handler == handler) - return; - reset(); + if (m_handler == handler) return; + finishTracks(); m_handler = handler; } @@ -540,8 +540,10 @@ TInputManager::trackEvent( if (getInputTracks().empty() && m_handler) m_handler->inputSetBusy(true); + ticks = fixTicks(ticks); TTrackP track = getTrack(deviceId, touchId, ticks, (bool)pressure, (bool)tilt); if (!track->finished()) { + ticks = fixTicks(ticks); double time = (double)(ticks - track->ticks())*TToolTimer::step - track->timeOffset(); addTrackPoint( track, @@ -561,6 +563,7 @@ TInputManager::keyEvent( TTimerTicks ticks, QKeyEvent *event ) { + ticks = fixTicks(ticks); state.keyEvent(press, key, ticks); processTracks(); bool result = m_handler && m_handler->inputKeyEvent(press, key, event, *this); @@ -578,6 +581,7 @@ TInputManager::buttonEvent( TInputState::Button button, TTimerTicks ticks ) { + ticks = fixTicks(ticks); state.buttonEvent(press, deviceId, button, ticks); processTracks(); if (m_handler) m_handler->inputButtonEvent(press, deviceId, button, *this); diff --git a/toonz/sources/tnztools/inputstate.cpp b/toonz/sources/tnztools/inputstate.cpp index 5251d1e..536dd85 100644 --- a/toonz/sources/tnztools/inputstate.cpp +++ b/toonz/sources/tnztools/inputstate.cpp @@ -2,6 +2,9 @@ #include <tools/inputstate.h> +#include <iomanip> +#include <QKeySequence> + //***************************************************************************************** // TKey static members @@ -80,3 +83,61 @@ TInputState::buttonFindAny(Button button, DeviceId &outDevice) { outDevice = DeviceId(); return ButtonState::Pointer(); } + + +namespace { + +template<typename T> +void printKey(const T &k, std::ostream &stream) + { stream << k; } + +template<> +void printKey<TKey>(const TKey &k, std::ostream &stream) { + stream << QKeySequence(k.key).toString().toStdString() << "[" << std::hex << k.key << std::dec; + if (k.generic) stream << "g"; + if (k.numPad) stream << "n"; + stream << "]"; +} + +template<typename T> +class Print { +public: + typedef T Type; + typedef TKeyHistoryT<Type> History; + typedef typename History::StatePointer StatePointer; + typedef typename History::StateMap StateMap; + typedef typename History::LockSet LockSet; + + static void print(const History &history, std::ostream &stream, const std::string &tab) { + const StateMap &states = history.getStates(); + stream << tab << "states: " << std::endl; + for(typename StateMap::const_iterator i = states.begin(); i != states.end(); ++i) { + stream << tab << "- " << i->first << std::endl; + for(StatePointer p = i->second; p; p = p->previous) { + stream << tab << "- - " << p->ticks << ": "; + printKey(p->value, stream); + stream << std::endl; + } + } + + const LockSet &locks = history.getLocks(); + stream << tab << "locks: "; + for(typename LockSet::const_iterator i = locks.begin(); i != locks.end(); ++i) { + if (i != locks.begin()) stream << ", "; + stream << *i; + } + stream << std::endl; + } +}; +} + + +void TInputState::print(std::ostream &stream, const std::string &tab) const { + stream << tab << "keys:" << std::endl; + Print<TKey>::print(*m_keyHistory, stream, tab + " "); + for(ButtonHistoryMap::const_iterator i = m_buttonHistories.begin(); i != m_buttonHistories.end(); ++i) { + stream << tab << "buttons[" << i->first << "]:" << std::endl; + Print<TKey>::print(*m_keyHistory, stream, tab + " "); + } +} + diff --git a/toonz/sources/tnztools/modifiersegmentation.cpp b/toonz/sources/tnztools/modifiersegmentation.cpp new file mode 100644 index 0000000..ec483fe --- /dev/null +++ b/toonz/sources/tnztools/modifiersegmentation.cpp @@ -0,0 +1,84 @@ + + +#include <tools/modifiers/modifiersegmentation.h> +#include <algorithm> + + +//***************************************************************************************** +// TModifierSegmentation implementation +//***************************************************************************************** + + +TModifierSegmentation::TModifierSegmentation(double precision): + precision(std::max(TTrack::epsilon, precision)), + precisionSqr(this->precision * this->precision) +{ } + + +void +TModifierSegmentation::addSegments( + TTrack &track, + const TTrackPoint &p0, + const TTrackPoint &p1, + int level) +{ + static const int maxRecursion = 10; + TPointD d = p1.position - p0.position; + + if (level >= maxRecursion || d.x*d.x + d.y*d.y <= precisionSqr) { + track.push_back(p1); + return; + } + + TTrackPoint p = track.modifier->calcPoint(0.5*(p0.originalIndex + p1.originalIndex)); + addSegments(track, p0, p, level + 1); + addSegments(track, p, p1, level + 1); +} + + +void +TModifierSegmentation::modifyTrack( + const TTrackP &track, + const TInputSavePoint::Holder &savePoint, + TTrackList &outTracks ) +{ + if (!track->handler) { + track->handler = new TTrackHandler(*track); + track->handler->tracks.push_back( + new TTrack( + new TTrackModifier(*track->handler) )); + } + + if (!track->changed() || track->handler->tracks.empty()) + return; + + TTrack &subTrack = *track->handler->tracks.front(); + outTracks.push_back(track->handler->tracks.front()); + + // remove points + int start = track->size() - track->pointsAdded; + if (start < 0) start = 0; + int subStart = subTrack.floorIndex(subTrack.indexByOriginalIndex(start)); + if (subStart < 0) subStart = 0; + if (subStart < subTrack.size() && subTrack[subStart].originalIndex + TTrack::epsilon < start) + ++subStart; + + while(subStart > 0 && subTrack[subStart-1].originalIndex + TTrack::epsilon >= start) + --subStart; + if (subStart < subTrack.size()) { + subTrack.pointsRemoved += subTrack.size() - subStart; + subTrack.truncate(subStart); + } + + // add points + TTrackPoint p0 = subTrack.modifier->calcPoint(start - 1); + for(int i = start; i < track->size(); ++i) { + TTrackPoint p1 = subTrack.modifier->calcPoint(i); + addSegments(subTrack, p0, p1); + p0 = p1; + } + subTrack.pointsAdded += subTrack.size() - subStart; + + track->pointsRemoved = 0; + track->pointsAdded = 0; +} diff --git a/toonz/sources/tnztools/modifiertangents.cpp b/toonz/sources/tnztools/modifiertangents.cpp new file mode 100644 index 0000000..c7c9f0f --- /dev/null +++ b/toonz/sources/tnztools/modifiertangents.cpp @@ -0,0 +1,124 @@ + + +#include <tools/modifiers/modifiertangents.h> + + +//***************************************************************************************** +// TModifierTangents::Modifier implementation +//***************************************************************************************** + + +TTrackPoint +TModifierTangents::Modifier::calcPoint(double originalIndex) { + double frac; + int i0 = original.floorIndex(originalIndex, &frac); + int i1 = original.ceilIndex(originalIndex); + TTrackPoint p = i0 < 0 ? TTrackPoint() + : TTrack::interpolationSpline( + original[i0], + original[i1], + i0 < (int)tangents.size() ? tangents[i0] : TTrackTangent(), + i1 < (int)tangents.size() ? tangents[i1] : TTrackTangent(), + frac ); + p.originalIndex = originalIndex; + return p; +} + + +//***************************************************************************************** +// TModifierTangents implementation +//***************************************************************************************** + + +void +TModifierTangents::modifyTrack( + const TTrackP &track, + const TInputSavePoint::Holder &savePoint, + TTrackList &outTracks ) +{ + if (!track->handler) { + track->handler = new TTrackHandler(*track); + track->handler->tracks.push_back( + new TTrack( + new Modifier(*track->handler) )); + } + + if (track->handler->tracks.empty()) + return; + + TTrack &subTrack = *track->handler->tracks.front(); + Modifier *modifier = dynamic_cast<Modifier*>(subTrack.modifier.getPointer()); + if (!modifier) + return; + + outTracks.push_back(track->handler->tracks.front()); + + if ( !track->changed() + && track->size() == subTrack.size() + && track->size() == (int)modifier->tangents.size() ) + return; + + if (!track->changed() && subTrack.size() == track->size() - 1) { + // add temporary point + modifier->tangents.push_back(TTrackTangent()); + subTrack.push_back(track->back()); + ++subTrack.pointsAdded; + } else { + // apply permanent changes + + // remove points + int start = track->size() - track->pointsAdded; + if (start < 0) start = 0; + if (start > 1) --start; + if (start < subTrack.size()) { + subTrack.pointsRemoved += subTrack.size() - start; + subTrack.truncate(start); + } + if (start < (int)modifier->tangents.size()) + modifier->tangents.erase( + modifier->tangents.begin() + start, + modifier->tangents.end() ); + + // add first point + int index = start; + if (index == 0) { + modifier->tangents.push_back(TTrackTangent()); + subTrack.push_back(track->back()); + ++index; + } + + // add points with tangents + while(index < track->size() - 1) { + const TTrackPoint &p0 = (*track)[index-1]; + const TTrackPoint &p1 = (*track)[index]; + const TTrackPoint &p2 = (*track)[index+1]; + double dt = p2.time - p0.time; + double k = dt > TTrack::epsilon ? (p1.time - p0.time)/dt : 0.5; + TTrackTangent tangent( + (p2.position - p0.position)*k, + (p2.pressure - p0.pressure)*k, + (p2.tilt - p0.tilt)*k ); + modifier->tangents.push_back(tangent); + subTrack.push_back(p1); + ++index; + } + + track->pointsRemoved = 0; + track->pointsAdded = 0; + subTrack.pointsAdded += index - start; + + // release previous key point + modifier->savePoint.reset(); + + if (track->finished()) { + // finish + modifier->tangents.push_back(TTrackTangent()); + subTrack.push_back(track->back()); + ++subTrack.pointsAdded; + } else { + // save key point + modifier->savePoint = savePoint; + } + } +} + diff --git a/toonz/sources/tnztools/modifiertest.cpp b/toonz/sources/tnztools/modifiertest.cpp index c74cf17..a52ce6c 100644 --- a/toonz/sources/tnztools/modifiertest.cpp +++ b/toonz/sources/tnztools/modifiertest.cpp @@ -1,7 +1,9 @@ -#include <tools/modifiertest.h> +#include <tools/modifiers/modifiertest.h> +// std includes +#include <cmath> //***************************************************************************************** // TModifierTest::Modifier implementation @@ -71,7 +73,7 @@ TModifierTest::modifyTrack( const double segmentSize = M_PI/180.0*10.0; if (!track->handler) { - if (track->getCurrentKeyState().isPressed(TKey(Qt::Key_T))) { + if (track->getCurrentKeyState().isPressed(TKey(Qt::Key_Alt))) { // TModifierTest::Handler for spiro track->handler = new Handler(*track); for(int i = 0; i < count; ++i) diff --git a/toonz/sources/tnztools/mypainttoonzbrush.cpp b/toonz/sources/tnztools/mypainttoonzbrush.cpp index cbf0728..3f97202 100644 --- a/toonz/sources/tnztools/mypainttoonzbrush.cpp +++ b/toonz/sources/tnztools/mypainttoonzbrush.cpp @@ -109,13 +109,18 @@ void Raster32PMyPaintSurface::setAntialiasing(bool value) { // //======================================================= -MyPaintToonzBrush::MyPaintToonzBrush(const TRaster32P &ras, - RasterController &controller, - const mypaint::Brush &brush) +MyPaintToonzBrush::MyPaintToonzBrush( + const TRaster32P &ras, + RasterController &controller, + const mypaint::Brush &brush, + bool interpolation +) : m_ras(ras) , m_mypaintSurface(m_ras, controller) , brush(brush) - , reset(true) { + , reset(true) + , interpolation(interpolation) +{ // read brush antialiasing settings float aa = this->brush.getBaseValue(MYPAINT_BRUSH_SETTING_ANTI_ALIASING); m_mypaintSurface.setAntialiasing(aa > 0.5f); @@ -135,7 +140,8 @@ void MyPaintToonzBrush::beginStroke() { void MyPaintToonzBrush::endStroke() { if (!reset) { - strokeTo(TPointD(current.x, current.y), current.pressure, 0.f); + if (interpolation) + strokeTo(TPointD(current.x, current.y), current.pressure, 0.f); beginStroke(); } } @@ -154,51 +160,55 @@ void MyPaintToonzBrush::strokeTo(const TPointD &point, double pressure, brush.setState(MYPAINT_BRUSH_STATE_ACTUAL_X, current.x); brush.setState(MYPAINT_BRUSH_STATE_ACTUAL_Y, current.y); return; - } else { - next.time = current.time + dtime; } - // accuracy - const double threshold = 1.0; - const double thresholdSqr = threshold * threshold; - const int maxLevel = 16; - - // set initial segment - Segment stack[maxLevel + 1]; - Params p0; - Segment *segment = stack; - Segment *maxSegment = segment + maxLevel; - p0.setMedian(previous, current); - segment->p1 = current; - segment->p2.setMedian(current, next); - - // process - while (true) { - double dx = segment->p2.x - p0.x; - double dy = segment->p2.y - p0.y; - if (dx * dx + dy * dy > thresholdSqr && segment != maxSegment) { - Segment *sub = segment + 1; - sub->p1.setMedian(p0, segment->p1); - segment->p1.setMedian(segment->p1, segment->p2); - sub->p2.setMedian(sub->p1, segment->p1); - segment = sub; - } else { - brush.strokeTo(m_mypaintSurface, segment->p2.x, segment->p2.y, - segment->p2.pressure, 0.f, 0.f, - segment->p2.time - p0.time); - if (segment == stack) break; - p0 = segment->p2; - --segment; + if (interpolation) { + next.time = current.time + dtime; + + // accuracy + const double threshold = 1.0; + const double thresholdSqr = threshold * threshold; + const int maxLevel = 16; + + // set initial segment + Segment stack[maxLevel + 1]; + Params p0; + Segment *segment = stack; + Segment *maxSegment = segment + maxLevel; + p0.setMedian(previous, current); + segment->p1 = current; + segment->p2.setMedian(current, next); + + // process + while (true) { + double dx = segment->p2.x - p0.x; + double dy = segment->p2.y - p0.y; + if (dx * dx + dy * dy > thresholdSqr && segment != maxSegment) { + Segment *sub = segment + 1; + sub->p1.setMedian(p0, segment->p1); + segment->p1.setMedian(segment->p1, segment->p2); + sub->p2.setMedian(sub->p1, segment->p1); + segment = sub; + } else { + brush.strokeTo(m_mypaintSurface, segment->p2.x, segment->p2.y, + segment->p2.pressure, 0.f, 0.f, + segment->p2.time - p0.time); + if (segment == stack) break; + p0 = segment->p2; + --segment; + } } - } - // keep parameters for future interpolation - previous = current; - current = next; + // keep parameters for future interpolation + previous = current; + current = next; - // shift time - previous.time = 0.0; - current.time = dtime; + // shift time + previous.time = 0.0; + current.time = dtime; + } else { + brush.strokeTo(m_mypaintSurface, point.x, point.y, pressure, 0.f, 0.f, dtime); + } } //---------------------------------------------------------------------------------- @@ -216,4 +226,4 @@ void MyPaintToonzBrush::updateDrawing(const TRasterCM32P rasCM, rasCM->copy(rasBackupCM->extract(targetRect), targetRect.getP00()); 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 f26aa60..5304fd7 100644 --- a/toonz/sources/tnztools/mypainttoonzbrush.h +++ b/toonz/sources/tnztools/mypainttoonzbrush.h @@ -120,10 +120,14 @@ private: bool reset; Params previous, current; + bool interpolation; public: - MyPaintToonzBrush(const TRaster32P &ras, RasterController &controller, - const mypaint::Brush &brush); + MyPaintToonzBrush( + const TRaster32P &ras, + RasterController &controller, + const mypaint::Brush &brush, + bool interpolation = false ); void beginStroke(); void endStroke(); void strokeTo(const TPointD &p, double pressure, double dtime);