diff --git a/toonz/sources/include/tools/assistant.h b/toonz/sources/include/tools/assistant.h index 86686f8..f63abb8 100644 --- a/toonz/sources/include/tools/assistant.h +++ b/toonz/sources/include/tools/assistant.h @@ -42,6 +42,7 @@ class TPropertyGroup; class TTool; class TToolViewer; class TAssistant; +class TAssistantBase; class TAssistantPoint; class TGuideline; @@ -134,7 +135,7 @@ public: TAssistantType(const TStringId &name): TMetaObjectType(name) { } TMetaObjectHandler* createHandler(TMetaObject &obj) const override; - virtual TAssistant* createAssistant(TMetaObject &obj) const + virtual TAssistantBase* createAssistant(TMetaObject &obj) const { return 0; } }; @@ -182,7 +183,7 @@ public: if (!alias5.empty()) registerAlias(TStringId(alias5)); } - TAssistant* createAssistant(TMetaObject &obj) const override + TAssistantBase* createAssistant(TMetaObject &obj) const override { return new Type(obj); } QString getLocalName() const override { QString localName = Type::getLocalName(); @@ -332,6 +333,7 @@ public: //***************************************************************************************** class DVAPI TAssistant : public TAssistantBase { + Q_DECLARE_TR_FUNCTIONS(TAssistant) protected: const TStringId m_idMagnetism; diff --git a/toonz/sources/include/tools/modifiers/modifierclone.h b/toonz/sources/include/tools/modifiers/modifierclone.h new file mode 100644 index 0000000..214e70f --- /dev/null +++ b/toonz/sources/include/tools/modifiers/modifierclone.h @@ -0,0 +1,55 @@ +#pragma once + +#ifndef MODIFIERCLONE_INCLUDED +#define MODIFIERCLONE_INCLUDED + +// TnzTools includes +#include + +#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 + +//=================================================================== + +//***************************************************************************************** +// TModifierClone definition +//***************************************************************************************** + +class DVAPI TModifierClone : public TInputModifier { +public: + class DVAPI Handler : public TMultiTrackHandler { + public: + TTrackP original; + inline explicit Handler(const TTrackP &original = TTrackP()): + original(original) { } + }; + + class DVAPI Interpolator : public TTrackInterpolator { + public: + const TTrackTransform transform; + inline Interpolator(TTrack &track, const TTrackTransform &transform): + TTrackInterpolator(track), transform(transform) { } + TTrackPoint interpolateFromOriginal(double originalIndex); + TTrackPoint interpolate(double index) override; + }; + + +public: + bool keepOriginals; + TTrackTransformList transforms; + + TModifierClone(bool keepOriginals = true); + + void modifyTrack( + const TTrack &track, + TTrackList &outTracks ) override; +}; + +#endif diff --git a/toonz/sources/include/tools/replicator.h b/toonz/sources/include/tools/replicator.h new file mode 100644 index 0000000..c7a1b93 --- /dev/null +++ b/toonz/sources/include/tools/replicator.h @@ -0,0 +1,47 @@ +#pragma once + +#ifndef REPLICATOR_INCLUDED +#define REPLICATOR_INCLUDED + +// TnzTools includes +#include +#include + +#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 + + +//***************************************************************************************** +// TReplicator definition +//***************************************************************************************** + +class DVAPI TReplicator : public TAssistantBase { + Q_DECLARE_TR_FUNCTIONS(TReplicator) +public: + static const int multiplierSoftLimit; + static const int multiplierLimit; + + TReplicator(TMetaObject &object); + + virtual int getMultipler() const; + virtual void getModifiers(const TAffine &toTool, TInputModifier::List &outModifiers) const; + + //! return summary multiplier, or 0 is no replicators found + static int scanReplicators( + TTool *tool, + TInputModifier::List *outModifiers, + bool draw, + bool enabledOnly, + bool markEnabled, + TImage *skipImage ); +}; + + +#endif diff --git a/toonz/sources/include/tools/track.h b/toonz/sources/include/tools/track.h index a8177b3..bc52bb9 100644 --- a/toonz/sources/include/tools/track.h +++ b/toonz/sources/include/tools/track.h @@ -36,6 +36,7 @@ class TTrack; class TTrackPoint; class TTrackTangent; +class TTrackTransform; class TTrackHandler; class TSubTrackHandler; class TMultiTrackHandler; @@ -49,6 +50,7 @@ typedef TSmartPointerT TTrackInterpolatorP; typedef std::vector TTrackPointList; typedef std::vector TTrackTangentList; +typedef std::vector TTrackTransformList; typedef std::vector TTrackList; //=================================================================== @@ -129,6 +131,43 @@ public: // TTrackHandler definition //***************************************************************************************** +class DVAPI TTrackTransform { +public: + TAffine transform; + TAffine tiltTransform; + double pressureScale; + double pressureOffset; + + inline explicit TTrackTransform( + const TAffine &transform = TAffine(), + const TAffine &tiltTransform = TAffine(), + double pressureScale = 1, + double pressureOffset = 0 + ): + transform(transform), + tiltTransform(tiltTransform), + pressureScale(pressureScale), + pressureOffset(pressureOffset) { } + + inline TTrackPoint apply(TTrackPoint p) const { + p.position = transform * p.position; + + TPointD t = tiltTransform * p.tilt; + p.tilt.x = t.x > -1 ? (t.x < 1 ? t.x : 1) : -1; + p.tilt.y = t.y > -1 ? (t.y < 1 ? t.y : 1) : -1; + + double pr = p.pressure*pressureScale + pressureOffset; + p.pressure = pr > 0 ? (pr < 1 ? pr : 1) : 0; + + return p; + } +}; + + +//***************************************************************************************** +// TTrackHandler definition +//***************************************************************************************** + class DVAPI TTrackHandler : public TSmartObject { }; diff --git a/toonz/sources/tnztools/CMakeLists.txt b/toonz/sources/tnztools/CMakeLists.txt index 9ca30f7..e347dc8 100644 --- a/toonz/sources/tnztools/CMakeLists.txt +++ b/toonz/sources/tnztools/CMakeLists.txt @@ -49,7 +49,9 @@ set(HEADERS ../include/tools/track.h ../include/tools/inputmanager.h ../include/tools/assistant.h + ../include/tools/replicator.h ../include/tools/modifiers/modifierassistants.h + ../include/tools/modifiers/modifierclone.h ../include/tools/modifiers/modifierline.h ../include/tools/modifiers/modifiersegmentation.h ../include/tools/modifiers/modifiersimplify.h @@ -126,7 +128,9 @@ set(SOURCES track.cpp inputmanager.cpp assistant.cpp + replicator.cpp modifiers/modifierassistants.cpp + modifiers/modifierclone.cpp modifiers/modifierline.cpp modifiers/modifiersegmentation.cpp modifiers/modifiersimplify.cpp @@ -138,6 +142,7 @@ set(SOURCES assistants/assistantvanishingpoint.cpp assistants/assistantline.cpp assistants/assistantellipse.cpp + assistants/replicatoraffine.cpp editassistantstool.cpp ) diff --git a/toonz/sources/tnztools/assistant.cpp b/toonz/sources/tnztools/assistant.cpp index 7171cfe..7b63920 100644 --- a/toonz/sources/tnztools/assistant.cpp +++ b/toonz/sources/tnztools/assistant.cpp @@ -364,6 +364,9 @@ TAssistantBase::updateProperty(const TStringId &name, const TVariant &value) { if (TDoubleProperty *doubleProperty = dynamic_cast(property)) { doubleProperty->setValue( value.getDouble() ); } else + if (TIntProperty *intProperty = dynamic_cast(property)) { + intProperty->setValue( (int)value.getDouble() ); + } else if (TStringProperty *stringProperty = dynamic_cast(property)) { stringProperty->setValue( to_wstring(value.getString()) ); } else @@ -389,6 +392,9 @@ TAssistantBase::onPropertyChanged(const TStringId &name) { if (TDoubleProperty *doubleProperty = dynamic_cast(property)) { data()[name].setDouble( doubleProperty->getValue() ); } else + if (TIntProperty *intProperty = dynamic_cast(property)) { + data()[name].setDouble( (double)intProperty->getValue() ); + } else if (TStringProperty *stringProperty = dynamic_cast(property)) { data()[name].setString( to_string(stringProperty->getValue()) ); } else @@ -696,11 +702,11 @@ TAssistant::scanAssistants( if (!enabledOnly || assistant->getEnabled()) { found = true; + if (!doSomething) return true; if (findGuidelines) for(int i = 0; i < positionsCount; ++i) assistant->getGuidelines(positions[i], imageToTrack, *outGuidelines); if (draw) assistant->draw(viewer, assistant->getEnabled() && markEnabled); - if (!doSomething) return true; } if (draw) glPopMatrix(); diff --git a/toonz/sources/tnztools/assistants/assistantellipse.cpp b/toonz/sources/tnztools/assistants/assistantellipse.cpp index e5b407b..29e2060 100644 --- a/toonz/sources/tnztools/assistants/assistantellipse.cpp +++ b/toonz/sources/tnztools/assistants/assistantellipse.cpp @@ -449,7 +449,6 @@ private: bool grid = getGrid(); bool ruler = getRestrictA() && getRestrictB(); bool concentric = !getRestrictA() && !getRestrictB(); - bool perspective = getPerspective(); drawSegment( ellipseMatrix*TPointD(-crossSize, 0.0), ellipseMatrix*TPointD( crossSize, 0.0), pixelSize, alpha); diff --git a/toonz/sources/tnztools/assistants/replicatoraffine.cpp b/toonz/sources/tnztools/assistants/replicatoraffine.cpp new file mode 100644 index 0000000..af88571 --- /dev/null +++ b/toonz/sources/tnztools/assistants/replicatoraffine.cpp @@ -0,0 +1,309 @@ + + +// TnzTools includes +#include +#include + + +// TnzCore includes +#include + + +//***************************************************************************************** +// TReplicatorAffine implementation +//***************************************************************************************** + +class TReplicatorAffine final : public TReplicator { + Q_DECLARE_TR_FUNCTIONS(TReplicatorAffine) +public: + const TStringId m_idFixScale; + const TStringId m_idFixAspect; + const TStringId m_idFixAngle; + const TStringId m_idFixSkew; + const TStringId m_idCount; + const TStringId m_idCountInv; + const TStringId m_idPressure; + +protected: + TAssistantPoint &m_center0; + TAssistantPoint &m_a0; + TAssistantPoint &m_b0; + TAssistantPoint &m_center1; + TAssistantPoint &m_a1; + TAssistantPoint &m_b1; + +public: + TReplicatorAffine(TMetaObject &object): + TReplicator(object), + m_idFixScale("fixScale"), + m_idFixAspect("fixAspect"), + m_idFixAngle("fixAngle"), + m_idFixSkew("fixSkew"), + m_idCount("count"), + m_idCountInv("countInv"), + m_idPressure("pressure"), + m_center0( addPoint("center0", TAssistantPoint::CircleCross) ), + m_a0 ( addPoint("a0", TAssistantPoint::CircleFill, TPointD(40, 0)) ), + m_b0 ( addPoint("b0", TAssistantPoint::Circle, TPointD( 0, 40)) ), + m_center1( addPoint("center1", TAssistantPoint::Circle, TPointD(50, 0)) ), + m_a1 ( addPoint("a1", TAssistantPoint::CircleFill, TPointD(90, 0)) ), + m_b1 ( addPoint("b1", TAssistantPoint::Circle, TPointD(50, 40)) ) + { + addProperty( new TBoolProperty(m_idFixScale.str(), getFixScale()) ); + addProperty( new TBoolProperty(m_idFixAspect.str(), getFixAspect()) ); + addProperty( new TBoolProperty(m_idFixAngle.str(), getFixAngle()) ); + addProperty( new TBoolProperty(m_idFixSkew.str(), getFixSkew()) ); + addProperty( new TIntProperty(m_idCount.str(), 0, multiplierSoftLimit - 1, getCount()) ); + addProperty( new TIntProperty(m_idCountInv.str(), 0, multiplierSoftLimit - 1, getCountInv()) ); + addProperty( new TDoubleProperty(m_idPressure.str(), 0.0, 2.0, getPressure()) ); + } + + + static QString getLocalName() + { return tr("Replicator Affine"); } + + + void updateTranslation() const override { + TReplicator::updateTranslation(); + setTranslation(m_idFixScale, tr("fix scale")); + setTranslation(m_idFixAspect, tr("fix aspect")); + setTranslation(m_idFixAngle, tr("fix angle")); + setTranslation(m_idFixSkew, tr("fix skew")); + setTranslation(m_idCount, tr("count")); + setTranslation(m_idCountInv, tr("inv. count")); + setTranslation(m_idPressure, tr("pressure")); + } + + + inline bool getFixScale() const + { return data()[m_idFixScale].getBool(); } + inline bool getFixAspect() const + { return data()[m_idFixAspect].getBool(); } + inline bool getFixAngle() const + { return data()[m_idFixAngle].getBool(); } + inline bool getFixSkew() const + { return data()[m_idFixSkew].getBool(); } + inline int getCount() const + { return (int)data()[m_idCount].getDouble(); } + inline int getCountInv() const + { return (int)data()[m_idCountInv].getDouble(); } + inline double getPressure() const + { return data()[m_idPressure].getDouble(); } + +protected: + inline void setCount(int x) + { if (getCount() != (double)x) data()[m_idCount].setDouble((double)x); } + inline void setCountInv(int x) + { if (getCountInv() != (double)x) data()[m_idCountInv].setDouble((double)x); } + inline void setPressure(double x) + { if (getPressure() != x) data()[m_idPressure].setDouble(x); } + + + void onSetDefaults() override { + setCount(1); + setPressure(1); + TReplicator::onSetDefaults(); + } + + + void onFixData() override { + TReplicator::onFixData(); + setCount( std::max(0, std::min(multiplierSoftLimit - 1, getCount())) ); + setCountInv( std::max(0, std::min(multiplierSoftLimit - 1, getCountInv())) ); + setPressure( std::max(0.0, std::min(2.0, getPressure())) ); + } + + + TAffine getAffine() const { + TPointD c, x, y; + c = m_center0.position; + x = m_a0.position - c; + y = m_b0.position - c; + TAffine t0( x.x, y.x, c.x, + x.y, y.y, c.y ); + c = m_center1.position; + x = m_a1.position - c; + y = m_b1.position - c; + TAffine t1( x.x, y.x, c.x, + x.y, y.y, c.y ); + return t1*t0.inv(); + } + + + void onFixPoints() override { + TPointD &c0 = m_center0.position; + TPointD &a0 = m_a0.position; + TPointD &b0 = m_b0.position; + + TPointD &c1 = m_center1.position; + TPointD &a1 = m_a1.position; + TPointD &b1 = m_b1.position; + + if (getFixScale()) { + double la0 = tdistance(a0, c0); + double lb0 = tdistance(b0, c0); + double la1 = tdistance(a1, c1); + double lb1 = tdistance(b1, c1); + a1 = la1 > TConsts::epsilon + ? (a1 - c1)*(la0/la1) + c1 + : a0 - c0 + c1; + b1 = lb1 > TConsts::epsilon + ? (b1 - c1)*(lb0/lb1) + c1 + : b0 - c0 + c1; + } else + if (getFixAspect()) { + double la0 = tdistance(a0, c0); + double lb0 = tdistance(b0, c0); + double la1 = tdistance(a1, c1); + double lb1 = tdistance(b1, c1); + if (la0 > TConsts::epsilon) + b1 = lb1 > TConsts::epsilon + ? (b1 - c1)*(lb0/lb1*la1/la0) + c1 + : (b0 - c0)*(la1/la0) + c1; + } + + if (getFixAngle()) { + double la0 = tdistance(a0, c0); + double lb0 = tdistance(b0, c0); + double la1 = tdistance(a1, c1); + double lb1 = tdistance(b1, c1); + if (la0 > TConsts::epsilon) + a1 = (a0 - c0)*(la1/la0) + c1; + if (lb0 > TConsts::epsilon) + b1 = (b0 - c0)*(lb1/lb0) + c1; + } else + if (getFixSkew()) { + TPointD da0 = a0 - c0; + TPointD pa0(-da0.y, da0.x); + double x = (b0 - c0)*da0; + double y = (b0 - c0)*pa0; + + TPointD da1 = a1 - c1; + TPointD pa1(-da1.y, da1.x); + TPointD p = da1*x + pa1*y; + double l = norm2(p); + if (l > TConsts::epsilon*TConsts::epsilon) + b1 = p*sqrt(tdistance2(b1, c1)/l) + c1; + } + } + + + void onMovePoint(TAssistantPoint &point, const TPointD &position) override { + TPointD pc0 = m_center0.position; + TPointD pc1 = m_center1.position; + point.position = position; + if (&point == &m_center0) { + TPointD d = m_center0.position - pc0; + m_a0.position += d; + m_b0.position += d; + m_a1.position += d; + m_b1.position += d; + m_center1.position += d; + } else + if (&point == &m_center1) { + TPointD d = m_center1.position - pc1; + m_a1.position += d; + m_b1.position += d; + } + onFixPoints(); + } + + + void onDataFieldChanged(const TStringId &name, const TVariant &value) override { + TReplicator::onDataFieldChanged(name, value); + if ( name == m_idFixScale + || name == m_idFixAspect + || name == m_idFixAngle + || name == m_idFixSkew ) + fixPoints(); + } + +public: + int getMultipler() const override + { return getCount() + 1; } + + + static TAffine makeTiltTransform(TAffine a) { + double l1 = a.a11*a.a11 + a.a21*a.a22; + double l2 = a.a11*a.a11 + a.a21*a.a22; + double l = std::max(l1, l2); + double k = l > TConsts::epsilon*TConsts::epsilon ? 1/sqrt(l) : 0; + a.a11 *= k; + a.a12 *= k; + a.a21 *= k; + a.a22 *= k; + a.a13 = a.a23 = 0; + return a; + } + + + void getModifiers( + const TAffine&, + TInputModifier::List &outModifiers ) const override + { + TAffine aff = getAffine(); + double pressure = getPressure(); + double pressureInv = fabs(pressure) > TConsts::epsilon ? 1/pressure : 0; + + struct { + int count; + TAffine aff; + double pressure; + } t[] = { + { getCount(), aff, pressure }, + { getCountInv(), aff.inv(), pressureInv }, + }; + + TModifierClone *modifier = new TModifierClone(); + for(int i = 0; i < 2; ++i) { + TTrackTransform tt; + for(int j = 0; j < t[i].count; ++j) { + tt.transform = t[i].aff * tt.transform; + tt.tiltTransform = makeTiltTransform(tt.transform); + tt.pressureScale *= t[i].pressure; + modifier->transforms.push_back(tt); + } + } + + outModifiers.push_back(modifier); + } + + + void draw(TToolViewer*, bool enabled) const override { + double alpha = getDrawingAlpha(enabled); + double pixelSize = sqrt(tglGetPixelSize2()); + + TPointD c = m_center0.position; + TPointD a = m_a0.position; + TPointD b = m_b0.position; + TAffine aff = getAffine(); + + // draw base + drawSegment(c, a, pixelSize, alpha); + drawSegment(c, b, pixelSize, alpha); + + // draw clones + TAffine t; + for(int i = getCount(); i > 0; --i) { + t = aff * t; + drawSegment(t*c, t*a, pixelSize, alpha); + drawSegment(t*c, t*b, pixelSize, alpha); + } + + // draw inverted clones + t = TAffine(); + aff = aff.inv(); + for(int i = getCountInv(); i > 0; --i) { + t = aff * t; + drawSegment(t*c, t*a, pixelSize, alpha); + drawSegment(t*c, t*b, pixelSize, alpha); + } + } +}; + + +//***************************************************************************************** +// Registration +//***************************************************************************************** + +static TAssistantTypeT replicatorAffine("replicatorAffine"); diff --git a/toonz/sources/tnztools/editassistantstool.cpp b/toonz/sources/tnztools/editassistantstool.cpp index ed217b9..ce4bb8d 100644 --- a/toonz/sources/tnztools/editassistantstool.cpp +++ b/toonz/sources/tnztools/editassistantstool.cpp @@ -159,15 +159,15 @@ protected: TPointD m_currentPosition; TGuidelineList m_currentGuidelines; - TMetaImage::Reader *m_reader; - TMetaImage *m_readImage; - TMetaObjectPC m_readObject; - const TAssistant *m_readAssistant; + TMetaImage::Reader *m_reader; + TMetaImage *m_readImage; + TMetaObjectPC m_readObject; + const TAssistantBase *m_readAssistant; - TMetaImage::Writer *m_writer; - TMetaImage *m_writeImage; - TMetaObjectP m_writeObject; - TAssistant *m_writeAssistant; + TMetaImage::Writer *m_writer; + TMetaImage *m_writeImage; + TMetaObjectP m_writeObject; + TAssistantBase *m_writeAssistant; Selection *selection; @@ -302,7 +302,7 @@ protected: && (**m_reader)[m_currentAssistantIndex] == m_currentAssistant ) { m_readObject = (**m_reader)[m_currentAssistantIndex]; - m_readAssistant = m_readObject->getHandler(); + m_readAssistant = m_readObject->getHandler(); if (mode == ModeAssistant) return true; if (m_readAssistant->findPoint(m_currentPointName)) { @@ -338,7 +338,7 @@ protected: && (**m_writer)[m_currentAssistantIndex] == m_currentAssistant ) { m_writeObject = (**m_writer)[m_currentAssistantIndex]; - m_writeAssistant = m_writeObject->getHandler(); + m_writeAssistant = m_writeObject->getHandler(); if ( (mode == ModeAssistant) || (mode == ModePoint && m_writeAssistant->findPoint(m_currentPointName)) ) { @@ -394,7 +394,7 @@ protected: if (Closer closer = read(ModeImage)) for(TMetaObjectListCW::iterator i = (*m_reader)->begin(); i != (*m_reader)->end(); ++i) if (*i) - if (const TAssistant *assistant = (*i)->getHandler()) + if (const TAssistantBase *assistant = (*i)->getHandler()) assistant->deselectAll(); if (updateOptionsBox) this->updateOptionsBox(); @@ -407,7 +407,7 @@ protected: for(TMetaObjectListCW::iterator i = (*m_reader)->begin(); i != (*m_reader)->end(); ++i) { if (!*i) continue; - const TAssistant *assistant = (*i)->getHandler(); + const TAssistantBase *assistant = (*i)->getHandler(); if (!assistant) continue; assistant->deselectAll(); @@ -516,7 +516,7 @@ public: resetCurrentPoint(false); if (Closer closer = write(ModeImage)) { TMetaObjectP object(new TMetaObject(m_newAssisnantType)); - if (TAssistant *assistant = object->getHandler()) { + if (TAssistantBase *assistant = object->getHandler()) { assistant->setDefaults(); assistant->move(position); assistant->selectAll(); @@ -597,13 +597,14 @@ public: if (Closer closer = read(ModeImage)) for(TMetaObjectListCW::iterator i = (*m_reader)->begin(); i != (*m_reader)->end(); ++i) if (*i) - if (const TAssistant *assistant = (*i)->getHandler()) + if (const TAssistantBase *base = (*i)->getHandler()) { - assistant->drawEdit(getViewer()); - assistant->getGuidelines( - position, - TAffine(), - m_currentGuidelines ); + base->drawEdit(getViewer()); + if (const TAssistant *assistant = dynamic_cast(base)) + assistant->getGuidelines( + position, + TAffine(), + m_currentGuidelines ); } // draw assistans and guidelines from other layers diff --git a/toonz/sources/tnztools/modifiers/modifierclone.cpp b/toonz/sources/tnztools/modifiers/modifierclone.cpp new file mode 100644 index 0000000..05d96b8 --- /dev/null +++ b/toonz/sources/tnztools/modifiers/modifierclone.cpp @@ -0,0 +1,75 @@ + +#include + + +//***************************************************************************************** +// TModifierClone::Interpolator implementation +//***************************************************************************************** + +TTrackPoint TModifierClone::Interpolator::interpolateFromOriginal(double originalIndex) + { return transform.apply( track.calcPointFromOriginal(originalIndex) ); } +TTrackPoint TModifierClone::Interpolator::interpolate(double index) + { return interpolateFromOriginal(track.originalIndexByIndex(index)); } + + +//***************************************************************************************** +// TModifierClone implementation +//***************************************************************************************** + +TModifierClone::TModifierClone(bool keepOriginals): + keepOriginals(keepOriginals) { } + +void TModifierClone::modifyTrack(const TTrack &track, + TTrackList &outTracks) +{ + if (!track.handler) { + Handler *handler = new Handler(); + track.handler = handler; + if (keepOriginals) { + handler->original = new TTrack(track); + new TTrackIntrOrig(*handler->original); + } + for(TTrackTransformList::const_iterator i = transforms.begin(); i != transforms.end(); ++i) { + handler->tracks.push_back(new TTrack(track)); + TTrack &subTrack = *handler->tracks.back(); + new Interpolator(subTrack, *i); + } + } + + Handler *handler = dynamic_cast(track.handler.getPointer()); + if (!handler) + return; + + if (handler->original) + outTracks.push_back(handler->original); + outTracks.insert(outTracks.end(), handler->tracks.begin(), handler->tracks.end()); + if (!track.changed()) + return; + + int start = track.size() - track.pointsAdded; + if (start < 0) start = 0; + + // process original + if (handler->original) { + TTrack &subTrack = *handler->original; + subTrack.truncate(start); + for (int i = start; i < track.size(); ++i) + subTrack.push_back(subTrack.pointFromOriginal(i), false); + subTrack.fix_to(track.fixedSize()); + } + + // process sub-tracks + for(TTrackList::iterator i = handler->tracks.begin(); i != handler->tracks.end(); ++i) { + TTrack &subTrack = **i; + Interpolator *intr = dynamic_cast(subTrack.getInterpolator().getPointer()); + if (!intr) + continue; + subTrack.truncate(start); + for (int i = start; i < track.size(); ++i) + subTrack.push_back(intr->interpolateFromOriginal(i), false); + subTrack.fix_to(track.fixedSize()); + } + + track.resetChanges(); +} + diff --git a/toonz/sources/tnztools/replicator.cpp b/toonz/sources/tnztools/replicator.cpp new file mode 100644 index 0000000..febbf9e --- /dev/null +++ b/toonz/sources/tnztools/replicator.cpp @@ -0,0 +1,115 @@ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + + + +const int TReplicator::multiplierSoftLimit = 32; +const int TReplicator::multiplierLimit = 256; + + +//************************************************************************ +// TReplicator implementation +//************************************************************************ + +TReplicator::TReplicator(TMetaObject &object): + TAssistantBase(object) { } + +//--------------------------------------------------------------------------------------------------- + +int +TReplicator::getMultipler() const + { return 1; } + +//--------------------------------------------------------------------------------------------------- + +void +TReplicator::getModifiers(const TAffine&, TInputModifier::List&) const + { } + +//--------------------------------------------------------------------------------------------------- + +int +TReplicator::scanReplicators( + TTool *tool, + TInputModifier::List *outModifiers, + bool draw, + bool enabledOnly, + bool markEnabled, + TImage *skipImage ) +{ + long long multiplier = 0; + + if (tool) + if (TToolViewer *viewer = tool->getViewer()) + if (TApplication *application = tool->getApplication()) + if (TXshLevelHandle *levelHandle = application->getCurrentLevel()) + if (TXshLevel *level = levelHandle->getLevel()) + if (TXshSimpleLevel *simpleLevel = level->getSimpleLevel()) + if (TFrameHandle *frameHandle = application->getCurrentFrame()) + if (TXsheetHandle *XsheetHandle = application->getCurrentXsheet()) + if (TXsheet *Xsheet = XsheetHandle->getXsheet()) + { + TPointD dpiScale = getCurrentDpiScale(simpleLevel, tool->getCurrentFid()); + int frame = frameHandle->getFrame(); + int count = Xsheet->getColumnCount(); + TAffine worldToTrack; + if ( tool->getToolType() & TTool::LevelTool + && !application->getCurrentObject()->isSpline() ) + { + worldToTrack.a11 /= dpiScale.x; + worldToTrack.a22 /= dpiScale.y; + } + + for(int i = 0; i < count; ++i) + if (TXshColumn *column = Xsheet->getColumn(i)) + if (column->isCamstandVisible()) + if (column->isPreviewVisible()) + if (TImageP image = Xsheet->getCell(frame, i).getImage(false)) + if (image != skipImage) + if (image->getType() == TImage::META) + if (TMetaImage *metaImage = dynamic_cast(image.getPointer())) + { + TAffine imageToTrack = worldToTrack * tool->getColumnMatrix(i); + if (draw) { glPushMatrix(); tglMultMatrix(imageToTrack); } + + TMetaImage::Reader reader(*metaImage); + for(TMetaObjectListCW::iterator i = reader->begin(); i != reader->end(); ++i) + if (*i) + if (const TReplicator *replicator = (*i)->getHandler()) + if (!enabledOnly || replicator->getEnabled()) + { + if (!multiplier) multiplier = 1; + bool enabled = replicator->getEnabled(); + + if (enabled) { + int m = replicator->getMultipler(); + if (m <= 0) m = 1; + multiplier *= m; + if (outModifiers) + replicator->getModifiers(imageToTrack, *outModifiers); + if (multiplier*m > multiplierLimit) + return multiplierLimit; + } + + if (draw) replicator->draw(viewer, enabled && markEnabled); + } + + if (draw) glPopMatrix(); + } + } + + return (int)multiplier; +} +