diff --git a/stuff/config/qss/Blue/Blue.qss b/stuff/config/qss/Blue/Blue.qss index 6197f0f..73e6677 100644 --- a/stuff/config/qss/Blue/Blue.qss +++ b/stuff/config/qss/Blue/Blue.qss @@ -1794,6 +1794,7 @@ SchematicViewer { qproperty-FxColumnColor: #5e5645; qproperty-PaletteColumnColor: #42756e; qproperty-MeshColumnColor: #594d75; + qproperty-MetaColumnColor: #8c8c8c; qproperty-ReferenceColumnColor: #4d5052; qproperty-TableColor: #62628c; qproperty-ActiveCameraColor: #4073a3; @@ -2343,6 +2344,9 @@ XsheetViewer { qproperty-MeshColumnColor: #594d75; qproperty-MeshColumnBorderColor: #423956; qproperty-SelectedMeshColumnColor: #656692; + qproperty-MetaColumnColor: #8c8c8c; + qproperty-MetaColumnBorderColor: #c8c8c8; + qproperty-SelectedMetaColumnColor: #a6a6a6; qproperty-SoundTextColumnColor: #a7a7a7; qproperty-SoundTextColumnBorderColor: #8e8e8e; qproperty-SelectedSoundTextColumnColor: #adb9c0; diff --git a/stuff/config/qss/Dark/Dark.qss b/stuff/config/qss/Dark/Dark.qss index 3d7b629..10652ea 100644 --- a/stuff/config/qss/Dark/Dark.qss +++ b/stuff/config/qss/Dark/Dark.qss @@ -1794,6 +1794,7 @@ SchematicViewer { qproperty-FxColumnColor: #5e5645; qproperty-PaletteColumnColor: #42756e; qproperty-MeshColumnColor: #594d75; + qproperty-MetaColumnColor: #8c8c8c; qproperty-ReferenceColumnColor: #3d3d3d; qproperty-TableColor: #62628c; qproperty-ActiveCameraColor: #4073a3; @@ -2343,6 +2344,9 @@ XsheetViewer { qproperty-MeshColumnColor: #594d75; qproperty-MeshColumnBorderColor: #423956; qproperty-SelectedMeshColumnColor: #656692; + qproperty-MetaColumnColor: #8c8c8c; + qproperty-MetaColumnBorderColor: #c8c8c8; + qproperty-SelectedMetaColumnColor: #a6a6a6; qproperty-SoundTextColumnColor: #a7a7a7; qproperty-SoundTextColumnBorderColor: #8e8e8e; qproperty-SelectedSoundTextColumnColor: #adb9c0; diff --git a/stuff/config/qss/Default/Default.qss b/stuff/config/qss/Default/Default.qss index 5908386..f502d4d 100644 --- a/stuff/config/qss/Default/Default.qss +++ b/stuff/config/qss/Default/Default.qss @@ -1794,6 +1794,7 @@ SchematicViewer { qproperty-FxColumnColor: #5e5645; qproperty-PaletteColumnColor: #42756e; qproperty-MeshColumnColor: #594d75; + qproperty-MetaColumnColor: #8c8c8c; qproperty-ReferenceColumnColor: #555555; qproperty-TableColor: #62628c; qproperty-ActiveCameraColor: #4073a3; @@ -2343,6 +2344,9 @@ XsheetViewer { qproperty-MeshColumnColor: #594d75; qproperty-MeshColumnBorderColor: #423956; qproperty-SelectedMeshColumnColor: #656692; + qproperty-MetaColumnColor: #8c8c8c; + qproperty-MetaColumnBorderColor: #c8c8c8; + qproperty-SelectedMetaColumnColor: #a6a6a6; qproperty-SoundTextColumnColor: #a7a7a7; qproperty-SoundTextColumnBorderColor: #8e8e8e; qproperty-SelectedSoundTextColumnColor: #adb9c0; diff --git a/stuff/config/qss/Default/less/Default.less b/stuff/config/qss/Default/less/Default.less index d2393cd..121ac30 100644 --- a/stuff/config/qss/Default/less/Default.less +++ b/stuff/config/qss/Default/less/Default.less @@ -454,6 +454,7 @@ @xsheet-ReferenceColumn-color: lighten(@bg, 5); @xsheet-PaletteColumn-color: #42756e; @xsheet-MeshColumn-color: #594d75; +@xsheet-MetaColumn-color: #8c8c8c; @xsheet-SoundTextColumn-color: #a7a7a7; @xsheet-SoundColumn-color: #578a8a; @xsheet-SoundColumnHL-color: #34FE5E; diff --git a/stuff/config/qss/Default/less/layouts/schematic.less b/stuff/config/qss/Default/less/layouts/schematic.less index 80ed4a0..349e7c5 100644 --- a/stuff/config/qss/Default/less/layouts/schematic.less +++ b/stuff/config/qss/Default/less/layouts/schematic.less @@ -13,6 +13,7 @@ SchematicViewer { qproperty-FxColumnColor: @xsheet-FxColumn-color; qproperty-PaletteColumnColor: @xsheet-PaletteColumn-color; qproperty-MeshColumnColor: @xsheet-MeshColumn-color; + qproperty-MetaColumnColor: @xsheet-MetaColumn-color; qproperty-ReferenceColumnColor: @xsheet-ReferenceColumn-color; qproperty-TableColor: saturate(lighten(@schematic-TableColor, @nodeLightness), @nodeSaturation); diff --git a/stuff/config/qss/Default/less/layouts/xsheet.less b/stuff/config/qss/Default/less/layouts/xsheet.less index 5b10940..5d7cbca 100644 --- a/stuff/config/qss/Default/less/layouts/xsheet.less +++ b/stuff/config/qss/Default/less/layouts/xsheet.less @@ -134,6 +134,10 @@ XsheetViewer { qproperty-MeshColumnBorderColor: desaturate(darken(@xsheet-MeshColumn-color, @columnBorderDarkness), @columnBorderDesaturation); qproperty-SelectedMeshColumnColor: mix(shade(@xsheet-MeshColumn-color, @cellHighlightLightness), @cellHighlightTintColor, @cellHighlightTintAmount); + qproperty-MetaColumnColor: @xsheet-MetaColumn-color; + qproperty-MetaColumnBorderColor: desaturate(darken(@xsheet-MetaColumn-color, @columnBorderDarkness), @columnBorderDesaturation); + qproperty-SelectedMetaColumnColor: mix(shade(@xsheet-MetaColumn-color, @cellHighlightLightness), @cellHighlightTintColor, @cellHighlightTintAmount); + qproperty-SoundTextColumnColor: @xsheet-SoundTextColumn-color; qproperty-SoundTextColumnBorderColor: desaturate(darken(@xsheet-SoundTextColumn-color, @columnBorderDarkness), @columnBorderDesaturation); qproperty-SelectedSoundTextColumnColor: mix(shade(@xsheet-SoundTextColumn-color, @cellHighlightLightness), @cellHighlightTintColor, @cellHighlightTintAmount); @@ -143,7 +147,7 @@ XsheetViewer { qproperty-SelectedSoundColumnColor: mix(shade(@xsheet-SoundColumn-color, @cellHighlightLightness), @cellHighlightTintColor, @cellHighlightTintAmount); qproperty-SoundColumnHlColor: @xsheet-SoundColumnHL-color; qproperty-SoundColumnTrackColor: @xsheet-SoundColumnTrack-color; - + qproperty-ActiveCameraColor: @xsheet-ActiveCamera-color; qproperty-SelectedActiveCameraColor: mix(shade(@xsheet-ActiveCamera-color, @cellHighlightLightness), @cellHighlightTintColor, @cellHighlightTintAmount); qproperty-OtherCameraColor: @xsheet-OtherCamera-color; diff --git a/stuff/config/qss/Default/less/themes/Light.less b/stuff/config/qss/Default/less/themes/Light.less index e49542a..72b8aed 100644 --- a/stuff/config/qss/Default/less/themes/Light.less +++ b/stuff/config/qss/Default/less/themes/Light.less @@ -206,6 +206,7 @@ @xsheet-ReferenceColumn-color: #c2c2c2; @xsheet-PaletteColumn-color: #a9d4ca; @xsheet-MeshColumn-color: #b8a2cf; +@xsheet-MetaColumn-color: #a8a8a8; @xsheet-SoundColumn-color: #aad6d6; @xsheet-SoundTextColumn-color: #c2c2c2; @xsheet-ActiveCamera-color: #b7dbfc; diff --git a/stuff/config/qss/Default/less/themes/Neutral.less b/stuff/config/qss/Default/less/themes/Neutral.less index a9723ad..9226fed 100644 --- a/stuff/config/qss/Default/less/themes/Neutral.less +++ b/stuff/config/qss/Default/less/themes/Neutral.less @@ -230,6 +230,7 @@ @xsheet-ReferenceColumn-color: #959595; @xsheet-PaletteColumn-color: #599586; @xsheet-MeshColumn-color: #8b73a7; +@xsheet-MetaColumnColor: #8c8c8c; @xsheet-SoundColumn-color: #749e9e; @xsheet-SoundColumnHL-color: #f5ffe6; @xsheet-SoundColumnTrack-color: rgba(0,0,0,0.8); diff --git a/stuff/config/qss/Light/Light.qss b/stuff/config/qss/Light/Light.qss index 6adc115..ebe296f 100644 --- a/stuff/config/qss/Light/Light.qss +++ b/stuff/config/qss/Light/Light.qss @@ -1794,6 +1794,7 @@ SchematicViewer { qproperty-FxColumnColor: #ceb694; qproperty-PaletteColumnColor: #a9d4ca; qproperty-MeshColumnColor: #b8a2cf; + qproperty-MetaColumnColor: #a8a8a8; qproperty-ReferenceColumnColor: #c2c2c2; qproperty-TableColor: #cbcbe4; qproperty-ActiveCameraColor: #b7dbfc; @@ -2343,6 +2344,9 @@ XsheetViewer { qproperty-MeshColumnColor: #b8a2cf; qproperty-MeshColumnBorderColor: #9278ac; qproperty-SelectedMeshColumnColor: #a49dc2; + qproperty-MetaColumnColor: #a8a8a8; + qproperty-MetaColumnBorderColor: #686868; + qproperty-SelectedMetaColumnColor: #c2c2c2; qproperty-SoundTextColumnColor: #c2c2c2; qproperty-SoundTextColumnBorderColor: #9c9c9c; qproperty-SelectedSoundTextColumnColor: #abb3b9; diff --git a/stuff/config/qss/Neutral/Neutral.qss b/stuff/config/qss/Neutral/Neutral.qss index 3b1a3b1..7ac5da9 100644 --- a/stuff/config/qss/Neutral/Neutral.qss +++ b/stuff/config/qss/Neutral/Neutral.qss @@ -1794,6 +1794,7 @@ SchematicViewer { qproperty-FxColumnColor: #928562; qproperty-PaletteColumnColor: #599586; qproperty-MeshColumnColor: #8b73a7; + qproperty-MetaColumnColor: #8c8c8c; qproperty-ReferenceColumnColor: #959595; qproperty-TableColor: #a4a4bf; qproperty-ActiveCameraColor: #6491be; @@ -2343,6 +2344,9 @@ XsheetViewer { qproperty-MeshColumnColor: #8b73a7; qproperty-MeshColumnBorderColor: #654f7e; qproperty-SelectedMeshColumnColor: #a18fc3; + qproperty-MetaColumnColor: #8c8c8c; + qproperty-MetaColumnBorderColor: #c8c8c8; + qproperty-SelectedMetaColumnColor: #a6a6a6; qproperty-SoundTextColumnColor: #a7a7a7; qproperty-SoundTextColumnBorderColor: #818181; qproperty-SelectedSoundTextColumnColor: #bbbfc3; diff --git a/toonz/sources/common/tcolor/tpixel.cpp b/toonz/sources/common/tcolor/tpixel.cpp index ffd82ac..053f86b 100644 --- a/toonz/sources/common/tcolor/tpixel.cpp +++ b/toonz/sources/common/tcolor/tpixel.cpp @@ -14,6 +14,8 @@ const TPixelRGBM32 TPixelRGBM32::Blue(0, 0, maxChannelValue); const TPixelRGBM32 TPixelRGBM32::Yellow(maxChannelValue, maxChannelValue, 0); const TPixelRGBM32 TPixelRGBM32::Cyan(0, maxChannelValue, maxChannelValue); const TPixelRGBM32 TPixelRGBM32::Magenta(maxChannelValue, 0, maxChannelValue); +const TPixelRGBM32 TPixelRGBM32::Gray(maxChannelValue/2, maxChannelValue/2, + maxChannelValue/2); const TPixelRGBM32 TPixelRGBM32::White(maxChannelValue, maxChannelValue, maxChannelValue); const TPixelRGBM32 TPixelRGBM32::Black(0, 0, 0); @@ -26,6 +28,8 @@ const TPixelRGBM64 TPixelRGBM64::Blue(0, 0, maxChannelValue); const TPixelRGBM64 TPixelRGBM64::Yellow(maxChannelValue, maxChannelValue, 0); const TPixelRGBM64 TPixelRGBM64::Cyan(0, maxChannelValue, maxChannelValue); const TPixelRGBM64 TPixelRGBM64::Magenta(maxChannelValue, 0, maxChannelValue); +const TPixelRGBM64 TPixelRGBM64::Gray(maxChannelValue/2, maxChannelValue/2, + maxChannelValue/2); const TPixelRGBM64 TPixelRGBM64::White(maxChannelValue, maxChannelValue, maxChannelValue); const TPixelRGBM64 TPixelRGBM64::Black(0, 0, 0); @@ -37,6 +41,7 @@ const TPixelD TPixelD::Blue(0, 0, 1); const TPixelD TPixelD::Yellow(1, 1, 0); const TPixelD TPixelD::Cyan(0, 1, 1); const TPixelD TPixelD::Magenta(1, 0, 1); +const TPixelD TPixelD::Gray(0.5, 0.5, 0.5); const TPixelD TPixelD::White(1, 1, 1); const TPixelD TPixelD::Black(0, 0, 0); const TPixelD TPixelD::Transparent(0, 0, 0, 0); diff --git a/toonz/sources/common/tgeometry/tgeometry.cpp b/toonz/sources/common/tgeometry/tgeometry.cpp index 7e8ea1d..d8bb6b6 100644 --- a/toonz/sources/common/tgeometry/tgeometry.cpp +++ b/toonz/sources/common/tgeometry/tgeometry.cpp @@ -95,12 +95,17 @@ bool TAffine::operator!=(const TAffine &a) const { //-------------------------------------------------------------------------------------------------- bool TAffine::isIdentity(double err) const { return ((a11 - 1.0) * (a11 - 1.0) + (a22 - 1.0) * (a22 - 1.0) + a12 * a12 + - a13 * a13 + a21 * a21 + a23 * a23) < err; + a13 * a13 + a21 * a21 + a23 * a23) <+ err; +} +//-------------------------------------------------------------------------------------------------- +bool TAffine::isZero(double err) const { + return ( a11*a11 + a12*a12 + a13*a13 + + a21*a21 + a22*a22 + a23*a23 ) <= err; } //-------------------------------------------------------------------------------------------------- bool TAffine::isTranslation(double err) const { return ((a11 - 1.0) * (a11 - 1.0) + (a22 - 1.0) * (a22 - 1.0) + a12 * a12 + - a21 * a21) < err; + a21 * a21) <= err; } //-------------------------------------------------------------------------------------------------- bool TAffine::isIsotropic(double err) const { @@ -116,6 +121,12 @@ TPointD TAffine::operator*(const TPointD &p) const { //-------------------------------------------------------------------------------------------------- +TPointD TAffine::transformDirection(const TPointD &p) const { + return TPointD(p.x * a11 + p.y * a12, p.x * a21 + p.y * a22); +} + +//-------------------------------------------------------------------------------------------------- + TRectD TAffine::operator*(const TRectD &rect) const { if (rect != TConsts::infiniteRectD) { TPointD p1 = *this * rect.getP00(), p2 = *this * rect.getP01(), @@ -141,6 +152,14 @@ TAffine TAffine::place(const TPointD &pIn, const TPointD &pOut) const { pOut.y - (a21 * pIn.x + a22 * pIn.y)); } +//-------------------------------------------------------------------------------------------------- + +TAffine TAffine::rotation(double angle) { + double s = sin(angle); + double c = cos(angle); + return TAffine(c, -s, 0, s, c, 0); +} + //================================================================================================== TRotation::TRotation(double degrees) { @@ -213,3 +232,313 @@ TScale::TScale(const TPointD ¢er, double s) { a22 = a.a22; a23 = a.a23; } + +//================================================================================================== + +TPoint4D TAffine4::operator*(const TPoint4D &b) const { + return TPoint4D( + b.x*a11 + b.y*a21 + b.z*a31 + b.w*a41, + b.x*a12 + b.y*a22 + b.z*a32 + b.w*a42, + b.x*a13 + b.y*a23 + b.z*a33 + b.w*a43, + b.x*a14 + b.y*a24 + b.z*a34 + b.w*a44 ); +} + +TAffine4 TAffine4::operator*(const TAffine4 &b) const { + return TAffine4( + *this * b.rowX(), + *this * b.rowY(), + *this * b.rowZ(), + *this * b.rowW() ); +} + +TAffine4 TAffine4::operator*=(const TAffine4 &b) + { return *this = *this * b; } + +TAffine4 TAffine4::inv() const { + TAffine4 r; + r.a11 = a22*(a33*a44 - a34*a43) + a23*(a34*a42 - a32*a44) + a24*(a32*a43 - a33*a42); + r.a12 = a21*(a34*a43 - a33*a44) + a23*(a31*a44 - a34*a41) + a24*(a33*a41 - a31*a43); + r.a13 = a21*(a32*a44 - a34*a42) + a22*(a34*a41 - a31*a44) + a24*(a31*a42 - a32*a41); + r.a14 = a21*(a33*a42 - a32*a43) + a22*(a31*a43 - a33*a41) + a23*(a32*a41 - a31*a42); + + double det = a11*r.a11 + a12*r.a21 + a13*r.a31 + a14*r.a41; + if (fabs(det) > TConsts::epsilon) det = 1.0/det; + r.a11 *= det; + r.a12 *= det; + r.a13 *= det; + r.a14 *= det; + + r.a21 = det*( a12*(a34*a43 - a33*a44) + a13*(a32*a44 - a34*a42) + a14*(a33*a42 - a32*a43) ); + r.a22 = det*( a11*(a33*a44 - a34*a43) + a13*(a34*a41 - a31*a44) + a14*(a31*a43 - a33*a41) ); + r.a23 = det*( a11*(a34*a42 - a32*a44) + a12*(a31*a44 - a34*a41) + a14*(a32*a41 - a31*a42) ); + r.a24 = det*( a11*(a32*a43 - a33*a42) + a12*(a33*a41 - a31*a43) + a13*(a31*a42 - a32*a41) ); + r.a31 = det*( a12*(a23*a44 - a24*a43) + a13*(a24*a42 - a22*a44) + a14*(a22*a43 - a23*a42) ); + r.a32 = det*( a11*(a24*a43 - a23*a44) + a13*(a21*a44 - a24*a41) + a14*(a23*a41 - a21*a43) ); + r.a33 = det*( a11*(a22*a44 - a24*a42) + a12*(a24*a41 - a21*a44) + a14*(a21*a42 - a22*a41) ); + r.a34 = det*( a11*(a23*a42 - a22*a43) + a12*(a21*a43 - a23*a41) + a13*(a22*a41 - a21*a42) ); + r.a41 = det*( a12*(a24*a33 - a23*a34) + a13*(a22*a34 - a24*a32) + a14*(a23*a32 - a22*a33) ); + r.a42 = det*( a11*(a23*a34 - a24*a33) + a13*(a24*a31 - a21*a34) + a14*(a21*a33 - a23*a31) ); + r.a43 = det*( a11*(a24*a32 - a22*a34) + a12*(a21*a34 - a24*a31) + a14*(a22*a31 - a21*a32) ); + r.a44 = det*( a11*(a22*a33 - a23*a32) + a12*(a23*a31 - a21*a33) + a13*(a21*a32 - a22*a31) ); + + return r; +} + +TAffine TAffine4::get2d(double z) const { + return TAffine( + a11, a21, z*a31 + a41, + a12, a22, z*a32 + a42 ); +} + +TAffine4 TAffine4::translation(double x, double y, double z) { + TAffine4 r; + r.rowW().x = x; + r.rowW().y = y; + r.rowW().z = z; + return r; +} + +TAffine4 TAffine4::scale(double x, double y, double z) { + TAffine4 r; + r.a11 = x; + r.a22 = y; + r.a33 = z; + return r; +} + +TAffine4 TAffine4::rotation(double x, double y, double z, double angle) { + TAffine4 r; + double k = x*x + y*y + z*z; + if (k > TConsts::epsilon*TConsts::epsilon) { + k = 1.0 / sqrt(k); + double s = sin(angle); + double c = cos(angle); + double ic = 1.0 - c; + x *= k; + y *= k; + z *= k; + + r.a11 = ic*x*x + c; + r.a12 = ic*x*y + s*z; + r.a13 = ic*z*x - s*y; + + r.a21 = ic*x*y - s*z; + r.a22 = ic*y*y + c; + r.a23 = ic*y*z + s*x; + + r.a31 = ic*z*x + s*y; + r.a32 = ic*y*z - s*x; + r.a33 = ic*z*z + c; + } + return r; +} + +TAffine4 TAffine4::rotationX(double angle) { + TAffine4 r; + double s = sin(angle); + double c = cos(angle); + r.a22 = c; + r.a23 = s; + r.a32 = -s; + r.a33 = c; + return r; +} + +TAffine4 TAffine4::rotationY(double angle) { + TAffine4 r; + double s = sin(angle); + double c = cos(angle); + r.a11 = c; + r.a13 = -s; + r.a31 = s; + r.a33 = c; + return r; +} + +TAffine4 TAffine4::rotationZ(double angle) { + TAffine4 r; + double s = sin(angle); + double c = cos(angle); + r.a11 = c; + r.a12 = s; + r.a21 = -s; + r.a22 = c; + return r; +} + +//================================================================================================== + +int TAngleRangeSet::find(Type a) const { + assert(!m_angles.empty()); + int i0 = 0, i1 = m_angles.size() - 1; + if (a < m_angles[0]) return i1; + if (m_angles[i1] <= a) return i1; + while(true) { + int i = (i1 + i0)/2; + if (i == i0) break; + if (m_angles[i] <= a) i0 = i; else i1 = i; + } + return i0; +} + +void TAngleRangeSet::insert(Type a) { + if (m_angles.empty()) { + m_angles.push_back(a); + } else { + int i = find(a); + if (m_angles[i] == a) + m_angles.erase(m_angles.begin() + i); + else if (a < m_angles[0]) + m_angles.insert(m_angles.begin(), a); + else + m_angles.insert(m_angles.begin() + i + 1, a); + } +} + +void TAngleRangeSet::doAdd(Type a0, Type a1) { + if (m_angles.empty()) { + if (!m_flip) set(a0, a1); + return; + } + + int i0 = find(a0); + int i1 = find(a1); + if (i0 == i1) { + bool visible = (i0%2 != 0) == m_flip; + if (m_angles[i0] != a0 && m_angles[i0] - a0 <= a1 - a0) { + if (visible) fill(); else set(a0, a1); + } else + if (!visible) { + if (a1 < a0) m_flip = true; + insert(a0); + insert(a1); + } + return; + } + + bool visible0 = (i0%2 != 0) == m_flip; + bool visible1 = (i1%2 != 0) == m_flip; + + // remove range (i0, i1] + i0 = (i0 + 1)%m_angles.size(); + if (i1 < i0) { + m_angles.erase(m_angles.begin() + i0, m_angles.end()); + m_angles.erase(m_angles.begin(), m_angles.begin() + i1 + 1); + } else { + m_angles.erase(m_angles.begin() + i0, m_angles.begin() + i1 + 1); + } + + // insert new angles if need + if (!visible0) insert(a0); + if (!visible1) insert(a1); + if (m_angles.empty() || a1 < a0) + m_flip = true; +} + +bool TAngleRangeSet::contains(Type a) const { + if (isEmpty()) return false; + if (isFull()) return true; + return (find(a)%2 != 0) == m_flip; +} + +bool TAngleRangeSet::check() const { + if (m_angles.size() % 2 != 0) + return false; + for(int i = 1; i < (int)m_angles.size(); ++i) + if (m_angles[i-1] >= m_angles[i]) + return false; + return true; +} + +void TAngleRangeSet::set(Type a0, Type a1) { + m_angles.clear(); + if (a0 < a1) { + m_flip = false; + m_angles.push_back(a0); + m_angles.push_back(a1); + } else + if (a0 > a1) { + m_flip = true; + m_angles.push_back(a1); + m_angles.push_back(a0); + } else { + m_flip = true; + } +} + +void TAngleRangeSet::set(const TAngleRangeSet &x, bool flip) { + if (&x == this) return; + m_flip = (x.isFlipped() != flip); + m_angles = x.angles(); +} + +void TAngleRangeSet::invert(Type a0, Type a1) { + if (a0 == a1) return; + if (isEmpty()) { set(a0, a1); return; } + if (isFull()) { set(a1, a0); return; } + if (a1 < a0) m_flip = !m_flip; + insert(a0); + insert(a1); +} + +void TAngleRangeSet::invert(const TAngleRangeSet &x) { + if (x.isEmpty()) { return; } + if (x.isFull()) { invert(); return; } + if (isEmpty()) { set(x); return; } + if (isFull()) { set(x, true); return; } + m_flip = m_flip != x.isFlipped(); + for(List::const_iterator i = x.angles().begin(); i != x.angles().end(); ++i) + insert(*i); +} + +void TAngleRangeSet::add(Type a0, Type a1) { + if (!isFull() && a0 != a1) + { if (isEmpty()) set(a0, a1); else doAdd(a0, a1); } +} + +void TAngleRangeSet::add(const TAngleRangeSet &x) { + if (&x == this || isFull() || x.isEmpty()) return; + if (isEmpty()) { set(x); return; } + if (x.isFull()) { fill(); return; } + for (Iterator i(x); i && !isFull(); ++i) + doAdd(i.a0(), i.a1()); +} + +void TAngleRangeSet::subtract(Type a0, Type a1) { + if (!isEmpty() && a0 != a1) { + if (isFull()) set(a1, a0); else + { invert(); doAdd(a0, a1); invert(); } + } +} + +void TAngleRangeSet::subtract(const TAngleRangeSet &x) { + if (isEmpty() || x.isEmpty()) return; + if (&x == this || x.isFull()) { clear(); return; } + if (isFull()) { set(x); invert(); return; } + + // a - b = !(!a + b) + invert(); + for (Iterator i(x); i && !isFull(); ++i) + doAdd(i.a0(), i.a1()); + invert(); +} + +void TAngleRangeSet::intersect(Type a0, Type a1) { + if (!isEmpty()) { + if (a0 == a1) clear(); else + if (isFull()) set(a0, a1); else + { invert(); doAdd(a1, a0); invert(); } + } +} + +void TAngleRangeSet::intersect(const TAngleRangeSet &x) { + if (&x == this || isEmpty() || x.isFull()) return; + if (x.isEmpty()) { clear(); return; } + if (isFull()) { set(x); return; } + + // a & b = !(!a + !b) + invert(); + for (Iterator i(x, true); i && !isFull(); ++i) + doAdd(i.a0(), i.a1()); + invert(); +} diff --git a/toonz/sources/common/tgl/tgl.cpp b/toonz/sources/common/tgl/tgl.cpp index 88c6989..bbe68cb 100644 --- a/toonz/sources/common/tgl/tgl.cpp +++ b/toonz/sources/common/tgl/tgl.cpp @@ -73,6 +73,16 @@ double tglGetPixelSize2() { //----------------------------------------------------------------------------- +TRectD tglGetBounds() { + TAffine4 modelview; + TAffine4 projection; + glGetDoublev(GL_MODELVIEW_MATRIX, modelview.a); + glGetDoublev(GL_PROJECTION_MATRIX, projection.a); + return (projection*modelview).get2d().inv() * TRectD(-1.0, -1.0, 1.0, 1.0); +} + +//----------------------------------------------------------------------------- + double tglGetTextWidth(const std::string &s, void *font) { double factor = 0.07; double w = 0; @@ -126,56 +136,25 @@ void tglDrawSegment(const TPointD &p1, const TPointD &p2) { void tglDrawCircle(const TPointD ¢er, double radius) { if (radius <= 0) return; - double pixelSize = 1; - int slices = 60; - - if (slices <= 0) slices = computeSlices(radius, pixelSize) >> 1; - - double step = M_PI / slices; - double step2 = 2.0 * step; + double pixelSize = sqrt( tglGetPixelSize2() ); + int slices = std::max(3, computeSlices(radius, pixelSize)); - double cos_t, sin_t, cos_ts, sin_ts, t; + double step = M_2PI / (double)slices; + double c = cos(step), s = sin(step); glPushMatrix(); glTranslated(center.x, center.y, 0.0); - glBegin(GL_LINES); - - cos_t = radius /* *1.0*/; - sin_t = 0.0; - for (t = 0; t + step < M_PI_2; t += step2) { - cos_ts = radius * cos(t + step); - sin_ts = radius * sin(t + step); - - glVertex2f(cos_t, sin_t); - glVertex2f(cos_ts, sin_ts); - - glVertex2f(-cos_t, sin_t); - glVertex2f(-cos_ts, sin_ts); - - glVertex2f(-cos_t, -sin_t); - glVertex2f(-cos_ts, -sin_ts); - - glVertex2f(cos_t, -sin_t); - glVertex2f(cos_ts, -sin_ts); - - cos_t = cos_ts; - sin_t = sin_ts; + glBegin(GL_LINE_STRIP); + + double x = radius, y = 0.0; + glVertex2d(x, y); + for(int i = slices - 1; i; --i) { + double xx = x; + x = c*xx - s*y; + y = s*xx + c*y; + glVertex2d(x, y); } - - cos_ts = 0.0; - sin_ts = radius /* *1.0*/; - - glVertex2f(cos_t, sin_t); - glVertex2f(cos_ts, sin_ts); - - glVertex2f(-cos_t, sin_t); - glVertex2f(-cos_ts, sin_ts); - - glVertex2f(-cos_t, -sin_t); - glVertex2f(-cos_ts, -sin_ts); - - glVertex2f(cos_t, -sin_t); - glVertex2f(cos_ts, -sin_ts); + glVertex2d(radius, 0.0); glEnd(); glPopMatrix(); @@ -256,6 +235,8 @@ void tglEnableLineSmooth(bool enable, double lineSize) { void tglEnablePointSmooth(double pointSize) { glEnable(GL_BLEND); + glEnable(GL_POINT_SMOOTH); + glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); glPointSize(pointSize); } diff --git a/toonz/sources/common/tiio/movsettings.cpp b/toonz/sources/common/tiio/movsettings.cpp index 4904050..6c86e8d 100644 --- a/toonz/sources/common/tiio/movsettings.cpp +++ b/toonz/sources/common/tiio/movsettings.cpp @@ -15,6 +15,8 @@ // 32-bit version //******************************************************************************* +#include "movsettings.h" + #ifdef _WIN32 #ifdef _MSC_VER #pragma warning(disable : 4996) @@ -95,8 +97,6 @@ esempio: buf[0] = 13 buf[1]=0 buf[2]=0 buf[3]=0 buf[4]=0 buf5]=231 allora str = "13 z 4 231" */ -#include "movsettings.h" - //------------------------------------------------ void visitAtoms(const QTAtomContainer &atoms, const QTAtom &parent, @@ -394,13 +394,13 @@ bool Tiio::isQuicktimeInstalled() { #include "tipc.h" #include "t32bitsrv_wrap.h" +#include "movsettings.h" + // MAC-Specific includes #ifdef MACOSX #include #endif -#include "movsettings.h" - //--------------------------------------------------------------------------- // Using 32-bit background server correspondence to achieve the same result diff --git a/toonz/sources/common/timage_io/tlevel_io.cpp b/toonz/sources/common/timage_io/tlevel_io.cpp index 3a6e379..0eab254 100644 --- a/toonz/sources/common/timage_io/tlevel_io.cpp +++ b/toonz/sources/common/timage_io/tlevel_io.cpp @@ -116,17 +116,8 @@ TLevelP TLevelReader::loadInfo() { TFilePath ln(it->getLevelName()); // cout << "try " << *it << " " << it->getLevelName() << endl; if (levelName == TFilePath(it->getLevelName())) { - try { - level->setFrame(it->getFrame(), TImageP()); - data.push_back(*it); - } catch (TMalformedFrameException tmfe) { - // skip frame named incorrectly warning to the user in the message - // center. - DVGui::warning(QString::fromStdWString( - tmfe.getMessage() + L": " + - QObject::tr("Skipping frame.").toStdWString())); - continue; - } + level->setFrame(it->getFrame(), TImageP()); + data.push_back(*it); } } if (!data.empty()) { diff --git a/toonz/sources/common/tmetaimage/tmetaimage.cpp b/toonz/sources/common/tmetaimage/tmetaimage.cpp new file mode 100644 index 0000000..1a43f6e --- /dev/null +++ b/toonz/sources/common/tmetaimage/tmetaimage.cpp @@ -0,0 +1,189 @@ + + +#include + + +//--------------------------------------------------------- + +TMetaObjectType::TMetaObjectType(const TStringId &name): name(name) + { registerAlias(name); } + +TMetaObjectType::~TMetaObjectType() { + // TMetaObject::unregisterType(*this); +} + +void +TMetaObjectType::registerAlias(const TStringId &alias) + { TMetaObject::registerType(alias, *this); } + +void +TMetaObjectType::unregisterAlias(const TStringId &alias) { + TMetaObject::Registry::const_iterator i = TMetaObject::getRegistry().find(alias); + if (i == TMetaObject::getRegistry().end() || i->second != this) { + std::cerr << "warning: trying to unregister not-registered alias (" << alias.str() + << ") of type of TMetaObject (" << name.str() << ") " << name.str() << std::endl; + } else { + TMetaObject::unregisterType(alias); + } +} + +//--------------------------------------------------------- + +TMetaObject::TMetaObject(const TMetaObject &other): + m_typeLink(linkedMap().end()), + m_previous(), + m_next(), + m_typeDesc(), + m_handler(), + m_data(*this, other.data()) + { linkToType(TStringId()); setType(other.getType()); } + +TMetaObject::TMetaObject(const TStringId &typeName, const TVariant &data): + m_typeLink(linkedMap().end()), + m_previous(), + m_next(), + m_typeDesc(), + m_handler(), + m_data(*this, data) + { linkToType(TStringId()); setType(typeName); } + +TMetaObject::TMetaObject(const std::string &typeName, const TVariant &data): + m_typeLink(linkedMap().end()), + m_previous(), + m_next(), + m_typeDesc(), + m_handler(), + m_data(*this, data) + { linkToType(TStringId()); setType(typeName); } + +TMetaObject::~TMetaObject() + { resetType(); unlinkFromType(); } + +TMetaObject::LinkedMap& +TMetaObject::linkedMap() + { static LinkedMap linkedMap; return linkedMap; } + +void +TMetaObject::linkToType(const TStringId &type) { + m_typeLink = linkedMap().insert( LinkedMap::value_type(type, LinkedList()) ).first; + m_previous = m_typeLink->second.last; + m_next = 0; + (m_previous ? m_previous->m_next : m_typeLink->second.first) = this; + m_typeLink->second.last = this; +} + +void +TMetaObject::unlinkFromType() { + (m_previous ? m_previous->m_next : m_typeLink->second.first) = m_next; + (m_next ? m_next->m_previous : m_typeLink->second.last ) = m_previous; + m_typeLink = linkedMap().end(); + m_previous = m_next = 0; +} + +void +TMetaObject::rewrap(const TStringId &type) { + const TMetaObjectType *typeDesc = findType(type); + if (typeDesc == m_typeDesc) return; + if (m_handler) delete m_handler; + m_typeDesc = typeDesc; + m_handler = m_typeDesc ? m_typeDesc->createHandler(*this) : 0; + onVariantChanged(m_data); +} + +void +TMetaObject::rewrapAll(const TStringId &type) { + LinkedMap::const_iterator it = linkedMap().find(type); + if (it != linkedMap().end()) + for(TMetaObject *i = it->second.first; i; i = i->m_next) + i->rewrap(it->first); +} + +void +TMetaObject::setType(const TStringId &name) { + if (m_typeLink->first != name) { + unlinkFromType(); + linkToType(name); + rewrap(name); + } +} + +void +TMetaObject::onVariantChanged(const TVariant &value) + { if (m_handler) m_handler->dataChanged(value); } + +void +TMetaObject::setDefaults() + { m_data.reset(); if (m_handler) m_handler->setDefaults(); } + +TMetaObject* +TMetaObject::clone() const + { return new TMetaObject(*this); } + +TMetaObject::Registry& +TMetaObject::registry() + { static Registry registry; return registry; } + +void +TMetaObject::registerType(const TStringId &name, const TMetaObjectType &type) { + if (registry().count(name)) + std::cerr << "warning: type of TMetaObject are already registered: " << name.str() << std::endl; + registry()[name] = &type; + + LinkedMap::const_iterator it = linkedMap().find(name); + if (it != linkedMap().end()) + for(TMetaObject *i = it->second.first; i; i = i->m_next) + i->rewrap(name); + rewrapAll(name); +} + +void +TMetaObject::unregisterType(const TStringId &name) { + if (!registry().count(name)) + std::cerr << "warning: trying to unregister non-registered alias of type of TMetaObject: " << name.str() << std::endl; + registry().erase(name); + rewrapAll(name); +} + +void +TMetaObject::unregisterType(const TMetaObjectType &type) { + Registry &r = registry(); + size_t s = r.size(); + for(Registry::iterator i = r.begin(); i != r.end();) + if (i->second == &type) + { r.erase(i++); rewrapAll(i->first); } else ++i; + if (s == r.size()) + std::cerr << "warning: trying to unregister non-registered type of TMetaObject: " << type.name.str() << std::endl; +} + +const TMetaObjectType* +TMetaObject::findType(const TStringId &name) { + const Registry &r = getRegistry(); + Registry::const_iterator i = r.find(name); + return i == r.end() ? 0 : i->second; +} + +//--------------------------------------------------------- + +TMetaImage::TMetaImage() + { } + +TMetaImage::TMetaImage(const TMetaImage &other) { + Reader reader(other); + m_objects.reserve(reader->size()); + for(TMetaObjectListCW::iterator i = reader->begin(); i != reader->end(); ++i) + if (*i) + m_objects.push_back( TMetaObjectP((*i)->clone()) ); +} + +TMetaImage::~TMetaImage() + { } + +TImage* +TMetaImage::cloneImage() const + { return new TMetaImage(*this); } + +TRectD +TMetaImage::getBBox() const + { return TRectD(); } + +//--------------------------------------------------------- diff --git a/toonz/sources/common/tproperty.cpp b/toonz/sources/common/tproperty.cpp index ea5e4f5..3bd89f4 100644 --- a/toonz/sources/common/tproperty.cpp +++ b/toonz/sources/common/tproperty.cpp @@ -51,20 +51,20 @@ TPropertyGroup *TPropertyGroup::clone() const { } void TPropertyGroup::add(TProperty *p) { - std::string name = p->getName(); + const TStringId &name = p->getNameId(); assert(m_table.find(name) == m_table.end()); m_properties.push_back(std::make_pair(p, true)); m_table[name] = p; } void TPropertyGroup::bind(TProperty &p) { - std::string name = p.getName(); + const TStringId &name = p.getNameId(); assert(m_table.find(name) == m_table.end()); m_properties.push_back(std::make_pair(&p, false)); m_table[name] = &p; } -TProperty *TPropertyGroup::getProperty(std::string name) { +TProperty *TPropertyGroup::getProperty(const TStringId &name) { PropertyTable::iterator i = m_table.find(name); if (i == m_table.end()) return 0; diff --git a/toonz/sources/common/tstringid.cpp b/toonz/sources/common/tstringid.cpp new file mode 100644 index 0000000..4131b76 --- /dev/null +++ b/toonz/sources/common/tstringid.cpp @@ -0,0 +1,72 @@ + + +#include + +#include +#include + +//--------------------------------------------------------- + +struct TStringId::StaticData { + Map map; + std::vector iterators; + Iterator none; + QMutex mutex; + StaticData() { + map[std::string()] = 0; + none = map.begin(); + iterators.push_back(none); + } + + static StaticData& instance() { + static StaticData data; + return data; + } +}; + +//--------------------------------------------------------- + +const TStringId::Iterator& +TStringId::none() + { return StaticData::instance().none; } + +//--------------------------------------------------------- + +TStringId::Iterator +TStringId::genIter(const std::string &str) { + StaticData &data = StaticData::instance(); + if (str.empty()) return data.none; + + QMutexLocker lock(&data.mutex); + Iterator i = data.map.find(str); + if (i == data.map.end()) { + i = data.map.insert(std::pair(str, (int)data.iterators.size())).first; + data.iterators.push_back(i); + } + return i; +} + +//--------------------------------------------------------- + +TStringId::Iterator +TStringId::findIter(int id) { + StaticData &data = StaticData::instance(); + if (id <= 0) return data.none; + + QMutexLocker lock(&data.mutex); + return id < (int)data.iterators.size() ? data.iterators[id] : data.none; +} + +//--------------------------------------------------------- + +TStringId::Iterator +TStringId::findIter(const std::string &str) { + StaticData &data = StaticData::instance(); + if (str.empty()) return data.none; + + QMutexLocker lock(&data.mutex); + Iterator i = data.map.find(str); + return i == data.map.end() ? data.none : i; +} + +//--------------------------------------------------------- diff --git a/toonz/sources/common/tsystem/tfilepath.cpp b/toonz/sources/common/tsystem/tfilepath.cpp index 4d99fed..3103efb 100644 --- a/toonz/sources/common/tsystem/tfilepath.cpp +++ b/toonz/sources/common/tsystem/tfilepath.cpp @@ -51,8 +51,8 @@ bool isNumbers(std::wstring str, int fromSeg, int toSeg) { // Let's check if it follows the format ####A (i.e 00001 or 00001a) int numDigits = 0, numLetters = 0; for (int pos = fromSeg + 1; pos < toSeg; pos++) { - if ((str[pos] >= 'A' && str[pos] <= 'Z') || - (str[pos] >= 'a' && str[pos] <= 'z')) { + if ((str[pos] >= L'A' && str[pos] <= L'Z') || + (str[pos] >= L'a' && str[pos] <= L'z')) { // Not the right format if we ran into a letter without first finding a // number if (!numDigits) return false; @@ -60,7 +60,7 @@ bool isNumbers(std::wstring str, int fromSeg, int toSeg) { // We'll keep track of the number of letters we find. // NOTE: From here on out we should only see letters numLetters++; - } else if (str[pos] >= '0' && str[pos] <= '9') { + } else if (str[pos] >= L'0' && str[pos] <= L'9') { // Not the right format if we ran into a number that followed a letter. // This format is not something we expect currently if (numLetters) return false; // not right format @@ -86,8 +86,46 @@ bool checkForSeqNum(QString type) { else return false; } + +bool parseFrame(const std::wstring &str, int &frame, QString &letter, int &padding) { + if (str.empty()) + return false; + + int i = 0, number = 0; + while(i < (int)str.size() && str[i] >= L'0' && str[i] <= L'9') + number = number * 10 + str[i++] - L'0'; + int digits = i; + wchar_t l = str[i] >= L'a' && str[i] <= L'z' ? str[i++] + : str[i] >= L'A' && str[i] <= L'Z' ? str[i++] + : L'\0'; + if (digits <= 0 || i < (int)str.size()) + return false; + + frame = number; + letter = l ? QString(1, QChar(l)) : QString(); + padding = str[0] == L'0' ? digits : 0; + return true; +} + }; // namespace + +TFrameId::TFrameId(const std::string &str, char s) + : m_frame(EMPTY_FRAME), m_letter(), m_zeroPadding(4), m_startSeqInd(s) +{ + if (str.empty()) return; + if (!parseFrame(to_wstring(str), m_frame, m_letter, m_zeroPadding)) + m_frame = NO_FRAME; +} + +TFrameId::TFrameId(const std::wstring &str, char s) + : m_frame(EMPTY_FRAME), m_letter(), m_zeroPadding(4), m_startSeqInd(s) +{ + if (str.empty()) return; + if (!parseFrame(str, m_frame, m_letter, m_zeroPadding)) + m_frame = NO_FRAME; +} + // TFrameId::operator string() const std::string TFrameId::expand(FrameFormat format) const { if (m_frame == EMPTY_FRAME) @@ -713,8 +751,8 @@ TFilePath TFilePath::getParentDir() const // noSlash! int i = getLastSlash(m_path); // cerco l'ultimo slash if (i < 0) { if (m_path.length() >= 2 && - (('a' <= m_path[0] && m_path[0] <= 'z') || - ('A' <= m_path[0] && m_path[0] <= 'Z')) && + ((L'a' <= m_path[0] && m_path[0] <= L'z') || + (L'A' <= m_path[0] && m_path[0] <= L'Z')) && m_path[1] == ':') return TFilePath(m_path.substr(0, 2)); else @@ -770,23 +808,7 @@ TFrameId TFilePath::getFrame() const { if (!checkForSeqNum(type) || !isNumbers(str, j, i)) return TFrameId(TFrameId::NO_FRAME); - int k, number = 0, digits = 0; - for (k = j + 1; k < i && iswdigit(str[k]); k++) { - digits++; - number = number * 10 + str[k] - L'0'; - } - char letter = '\0'; - if (iswalpha(str[k])) letter = str[k++] + ('a' - L'a'); - - // if (number == 0 || k < i) // || letter!='\0') - // throw TMalformedFrameException( - // *this, - // str + L": " + QObject::tr("Malformed frame name").toStdWString()); - int padding = 0; - - if (str[j + 1] == '0') padding = digits; - - return TFrameId(number, letter, padding, str[j]); + return TFrameId(str.substr(j+1, i-j-1), str[j]); } //----------------------------------------------------------------------------- @@ -1166,4 +1188,4 @@ TFilePath::TFilePathInfo TFilePath::analyzePath() const { info.fId = TFrameId(TFrameId::NO_FRAME, 0, 0); // initialize with NO_PAD info.extension = QString(); return info; -} \ No newline at end of file +} diff --git a/toonz/sources/common/tvariant.cpp b/toonz/sources/common/tvariant.cpp new file mode 100644 index 0000000..40524b8 --- /dev/null +++ b/toonz/sources/common/tvariant.cpp @@ -0,0 +1,534 @@ + +#include + +#include +#include +#include + + +//--------------------------------------------------------- + +int +TVariantPath::compare( + const TVariantPath &a, int beginA, + const TVariantPath &b, int beginB, int count ) +{ + assert(beginA >= 0 && beginA <= (int)a.size()); + assert(beginB >= 0 && beginB <= (int)b.size()); + if (count == 0) return 0; + int countA = std::min(count, (int)a.size() - beginA); + int countB = std::min(count, (int)b.size() - beginB); + count = std::min(countA, countB); + + TVariantPath::const_iterator ia = a.begin() + beginA; + TVariantPath::const_iterator ib = b.begin() + beginB; + for(int i = 0; i < count; ++i, ++ia, ++ib) + if ((*ia) < (*ib)) return -1; else + if ((*ib) < (*ia)) return 1; + return countA < countB ? -1 + : countB < countA ? 1 : 0; +} + +//--------------------------------------------------------- + +void +TVariant::setParentForChilds() { + if (m_type == List) { + for(TVariantList::iterator i = m_list.begin(); i != m_list.end(); ++i) + i->setParent(*this); + } else + if (m_type == Map) { + for(TVariantMap::iterator i = m_map.begin(); i != m_map.end(); ++i) + i->second.setParent(*this, i->first); + } +} + +//--------------------------------------------------------- + +const TVariant& +TVariant::blank() { + static const TVariant blank; + return blank; +} + +//--------------------------------------------------------- + +void +TVariant::resize(int size) { + setType(List); + int prevSize = (int)m_list.size(); + if (prevSize == size) return; + m_list.resize(size); + if (prevSize < size) + for(TVariantList::iterator i = m_list.begin() + prevSize; i != m_list.end(); ++i) + i->setParent(*this); + touch(); +} + +//--------------------------------------------------------- + +void +TVariant::insert(int index, const TVariant &v) { + resize(std::max((int)m_list.size(), index)); + m_list.insert(m_list.begin() + index, v); + m_list[index].setParent(*this); + touch(); +} + +//--------------------------------------------------------- + +void +TVariant::remove(int index) { + if (m_type == List && index >= 0 && index < (int)m_list.size()) + { m_list.erase(m_list.begin() + index); touch(); } +} + +//--------------------------------------------------------- + +TVariant& +TVariant::operator[] (int index) { + setType(List); + assert(index >= 0); + int prevSize = (int)m_list.size(); + if (index >= prevSize) { + m_list.resize(index + 1); + for(TVariantList::iterator i = m_list.begin() + prevSize; i != m_list.end(); ++i) + i->setParent(*this); + touch(); + } + return m_list[index]; +} + +//--------------------------------------------------------- + +TVariant& +TVariant::operator[] (const TStringId &field) { + setType(Map); + TVariant &result = m_map[field]; + if (!result.m_parent) { + result.setParent(*this, field); + touch(); + } + return result; +} + +//--------------------------------------------------------- + +bool +TVariant::remove(const TStringId &field) { + if (m_type == Map && m_map.erase(field)) + { touch(); return true; } + return false; +} + +//--------------------------------------------------------- + +const TVariant& +TVariant::byPath(const TVariantPath &path, int begin, int end) const { + if ((int)path.size() <= begin || begin >= end) return *this; + if (isNone()) return blank(); + return (*this)[path[begin]].byPath(path, begin + 1, end); +} + +//--------------------------------------------------------- + +TVariant& +TVariant::byPath(const TVariantPath &path, int begin, int end) { + if ((int)path.size() <= begin || begin >= end) return *this; + return (*this)[path[begin]].byPath(path, begin + 1, end); +} + +//--------------------------------------------------------- + +int +TVariant::getParentPathSize(const TVariant &parent) const { + int ac = 0; + for(const TVariant *a = this; a; a = a->parent(), ++ac) + if (a == &parent) return ac; + return -1; +} + +//--------------------------------------------------------- + +bool +TVariant::getParentPath(TVariantPath &outPath, const TVariant &parent) const { + if (!m_parent) + { outPath.clear(); return false; } + if (m_parent == this) + { outPath.clear(); return true; } + if (m_parent->getParentPath(outPath)) + { outPath.push_back(parentPathEntry()); return true; } + return false; +} + +//--------------------------------------------------------- + +bool +TVariant::getChildPathEntry(const TVariant &child, TVariantPathEntry &outEntry) const { + for(const TVariant *a = &child; a->parent(); a = a->parent()) + if (a->parent() == this) + { outEntry = a->parentPathEntry(); return true; } + outEntry = TVariantPathEntry(); + return false; +} + +//--------------------------------------------------------- + +bool +TVariant::isChildOf(const TVariant &other) const { + for(const TVariant *a = this->m_parent; a; a = a->m_parent) + if (a == &other) return true; + return false; +} + +//--------------------------------------------------------- + +bool +TVariant::isChildOrEqual(const TVariant &other) const { + for(const TVariant *a = this; a; a = a->m_parent) + if (a == &other) return true; + return false; +} + +//--------------------------------------------------------- + +const TVariant* +TVariant::findCommonParent(const TVariant &other) const { + if (m_root != other.m_root) return NULL; + const TVariant *a = this, *b = &other; + int ac = 0, bc = 0; + while(a->m_parent) a = a->m_parent, ++ac; + while(b->m_parent) b = b->m_parent, ++bc; + + a = this, b = &other; + while(ac > bc) a = a->m_parent, --ac; + while(bc > ac) b = b->m_parent, --bc; + + while(true) { + if (a == b) return a; + if (ac == 0) break; + --ac, a = a->m_parent, b = b->m_parent; + } + + return NULL; +} + +//--------------------------------------------------------- + +size_t +TVariant::getMemSize() const { + size_t s = sizeof(*this); + for(TVariantList::const_iterator i = m_list.begin(); i != m_list.end(); ++i) + s += i->getMemSize(); + for(TVariantMap::const_iterator i = m_map.begin(); i != m_map.end(); ++i) + s += sizeof(*i) - sizeof(*this) + i->second.getMemSize(); + return s; +} + +//--------------------------------------------------------- + +void +TVariant::toStream(std::ostream &stream, bool pretty, int level) const { + struct Writer { + const TVariant &data; + std::ostream &stream; + bool pretty; + int level; + + Writer(const TVariant &data, std::ostream &stream, bool pretty, int level): + data(data), stream(stream), pretty(pretty), level(level) { } + + void writeNewLine() + { if (pretty) stream << std::endl; } + void writeSpace() + { if (pretty) stream << " "; } + void writeTab(int level) + { if (pretty) for(int i = 2*level; i; --i) stream << " "; } + void writeChar(char c) + { stream.put(c); } + void writeWord(const char *word) + { stream << word; } + + void writeString(const std::string &str) { + writeWord("\""); + for(const char *c = str.c_str(); *c; ++c) { + switch (*c) { + case '\"': writeWord("\\\""); break; + case '\\': writeWord("\\\\"); break; + case '\b': writeWord("\\b"); break; + case '\f': writeWord("\\f"); break; + case '\n': writeWord("\\n"); break; + case '\r': writeWord("\\r"); break; + case '\t': writeWord("\\t"); break; + default: writeChar(*c); break; + } + } + writeWord("\""); + } + + void writeDouble(double x) { + char buf[256]; + snprintf(buf, sizeof(buf), "%.12lg", x); + stream << buf; + } + + void writeList(const TVariantList &list) { + writeWord("["); + if (!list.empty()) { + writeNewLine(); + TVariantList::const_iterator i = list.begin(); + while(true) { + writeTab(level + 1); + i->toStream(stream, pretty, level + 1); + if (++i == list.end()) { writeNewLine(); break; } + writeWord(","); + writeNewLine(); + } + writeTab(level); + } else writeSpace(); + writeWord("]"); + } + + void writeMap(const TVariantMap &map) { + writeWord("{"); + if (!map.empty()) { + writeNewLine(); + TVariantMap::const_iterator i = map.begin(); + while(true) { + writeTab(level + 1); + writeString(i->first.str()); + writeWord(":"); + writeSpace(); + i->second.toStream(stream, pretty, level + 1); + if (++i == map.end()) { writeNewLine(); break; } + writeWord(","); + writeNewLine(); + } + writeTab(level); + } else writeSpace(); + writeWord("}"); + } + + void write() { + switch(data.getType()) { + case Bool: writeWord(data.getBool() ? "true" : "false"); break; + case Double: writeDouble(data.getDouble()); break; + case String: writeString(data.getString()); break; + case List: writeList(data.getList()); break; + case Map: writeMap(data.getMap()); break; + case None: + default: writeWord("null"); break; + } + if (!stream) throw TException("write to stream failed"); + } + }; + + Writer(*this, stream, pretty, level).write(); +} + +//--------------------------------------------------------- + +void +TVariant::fromStream(std::istream &stream, int *currentRow, int *currentCol) { + struct Reader { + TVariant &data; + std::istream &stream; + int &row; + int &col; + Reader(TVariant &data, std::istream &stream, int &row, int &col): + data(data), stream(stream), row(row), col(col) { } + + void warning(const std::string &msg) + { std::cerr << "TVariant load:" << row << ":" << col << ": " << msg << std::endl; } + void error(const std::string &msg) + { throw TVariantSyntaxException(row, col, msg); } + void error() + { error("cannot recognize type of data"); } + + int peek() + { return stream.peek(); } + + int get() { + int c = stream.get(); + if (c == '\n') ++row, col = 1; else ++col; + if (!stream) error("unexpected end of file"); + return c; + } + + void skipSpaces() + { while(isspace(peek())) get(); } + + bool readWord(const char *word) { + if (peek() != *word) return false; + while(*word) + if (get() == *word) ++word; else error(); + return true; + } + + bool readNull() { + if (readWord("null") || peek() == EOF) + { data.reset(); return true; } + return false; + } + + bool readBool() { + if (readWord("true")) { data.setBool(true); return true; } + if (readWord("false")) { data.setBool(false); return true; } + return false; + } + + bool isdouble(int c) + { return isdigit(c) || c == '-' || c == '+' || c == '.'; } + + bool readDouble() { + if (!isdouble(peek())) return false; + std::string str; str.reserve(20); + while(isdouble(peek()) || isalpha(peek())) str.push_back((char)get()); + double d = 0.0; + try { d = std::stod(str); } + catch (const std::exception &e) { warning("wrong number: " + str); } + data.setDouble(d); + return true; + } + + void readHexUnicode(std::string &str) { + // read utf16 code + // JSON standard requires exact four hex digits + // but we're kind and allows 0-4 hex digits + int code = 0; + for(int i = 0; i < 4; ++i) { + char c = peek(); + if (c >= '0' && c <= '9') + code = 16*code + get() - '0'; + else if (c >= 'a' && c <= 'f') + code = 16*code + get() - 'a'; + else if (c >= 'A' && c <= 'F') + code = 16*code + get() - 'A'; + else break; + } + if (code == 0) + { warning("\\u token with zero code"); return; } + + // 16 bits of utf16 character be encoded up to three utf8 bytes + // in the following format: + // 11000xxx 10xxxxxx 0xxxxxxx + if (code >= 1 << 13) { // 11000xxx + str.push_back((char)(192 | (code >> 13))); + code &= (1 << 13) - 1; + } + if (code >= 1 << 6) { // 10xxxxxx + str.push_back((char)(128 | (code >> 6))); + code &= (1 << 6) - 1; + } + str.push_back((char)code); // 0xxxxxxx + } + + void readString(std::string &str) { + if (get() != '\"') error("expected quote"); + while(true) { + int c = get(); + if (c == '\"') break; + else + if (c == '\\') { + switch(int cc = get()) { + case '\"': str.push_back('\"'); break; + case '\\': str.push_back('\\'); break; + case '/': str.push_back( '/'); break; + case 'b': str.push_back('\b'); break; + case 'f': str.push_back('\f'); break; + case 'n': str.push_back('\n'); break; + case 'r': str.push_back('\r'); break; + case 't': str.push_back('\t'); break; + case 'u': readHexUnicode(str); break; + default: str.push_back((char)cc); break; + } + } else + str.push_back((char)c); + } + } + + bool readString() { + if (peek() != '\"') return false; + std::string str; + readString(str); + data.setString(str); + return true; + } + + bool readList() { + if (peek() != '[') return false; + get(); // skip bracket + data.reset(); + data.setType(List); + while(true) { + skipSpaces(); + if (peek() == ']') { get(); break; } + if (data.size() && get() != ',') error("expected comma or close bracket"); + skipSpaces(); + if (peek() == ']') { get(); break; } // to allow comma at the end + data[data.size()].fromStream(stream, &row, &col); + } + return true; + } + + bool readMap() { + if (peek() != '{') return false; + get(); // skip brace + data.reset(); + data.setType(Map); + while(true) { + skipSpaces(); + if (peek() == '}') { get(); break; } + if (data.size() && get() != ',') error("expected comma or close brace"); + skipSpaces(); + if (peek() == '}') { get(); break; } // to allow comma at the end + std::string key; + readString(key); + skipSpaces(); + if (get() != ':') error("expected colon"); + if (data.contains(key)) warning("duplicate key: " + key); + data[key].fromStream(stream, &row, &col); + } + return true; + } + + void read() { + skipSpaces(); + if ( !readNull() + && !readBool() + && !readDouble() + && !readString() + && !readList() + && !readMap() ) + error(); + } + }; + + reset(); + int row = 1, col = 1; + Reader( + *this, + stream, + (currentRow ? *currentRow : row), + (currentCol ? *currentCol : col) ).read(); +} + +//--------------------------------------------------------- + +std::string +TVariant::toString(bool pretty, int level) const { + std::stringstream stream(std::ios_base::out); + toStream(stream, pretty, level); + return stream.str(); +} + +//--------------------------------------------------------- + +void +TVariant::fromString(const std::string &str, int *currentRow, int *currentCol) { + std::stringstream stream(str, std::ios_base::in); + fromStream(stream, currentRow, currentCol); +} + +//--------------------------------------------------------- + diff --git a/toonz/sources/image/3gp/tiio_3gp.h b/toonz/sources/image/3gp/tiio_3gp.h index 6d11800..931b09a 100644 --- a/toonz/sources/image/3gp/tiio_3gp.h +++ b/toonz/sources/image/3gp/tiio_3gp.h @@ -7,6 +7,12 @@ #include "tiio_3gp_proxy.h" #else +// Toonz includes +#include "tlevel_io.h" +#include "tthreadmessage.h" +#include "tcommon.h" + +// Windows include #include namespace QuickTime { @@ -36,9 +42,6 @@ namespace QuickTime { #undef QT_uint_fast16_t } -#include "tlevel_io.h" -#include "tthreadmessage.h" - using namespace QuickTime; class TImageWriter3gp; diff --git a/toonz/sources/image/3gp/tiio_3gpM.h b/toonz/sources/image/3gp/tiio_3gpM.h index e77f67f..14f8a3e 100644 --- a/toonz/sources/image/3gp/tiio_3gpM.h +++ b/toonz/sources/image/3gp/tiio_3gpM.h @@ -7,16 +7,16 @@ #include "tiio_3gp_proxy.h" #else +#include "tlevel_io.h" +#include "tthread.h" +#include "tthreadmessage.h" + #include #include #include #include #include "tquicktime.h" -#include "tthreadmessage.h" - -#include "tlevel_io.h" -#include "tthread.h" class TImageWriter3gp; class TImageReader3gp; diff --git a/toonz/sources/image/3gp/tiio_3gpW.cpp b/toonz/sources/image/3gp/tiio_3gpW.cpp index 0d4d0d8..553b62b 100644 --- a/toonz/sources/image/3gp/tiio_3gpW.cpp +++ b/toonz/sources/image/3gp/tiio_3gpW.cpp @@ -8,13 +8,20 @@ #include "tsound.h" #include "tconvert.h" #include "tpropertytype.h" -#include "../mov/tiio_mov.h" -#include "movsettings.h" #include "trasterimage.h" #include "tsystem.h" +// movesettings deps, must be included before QuickTime includes +#include "texception.h" +#include "tpropertytype.h" +#include "tproperty.h" + +// following includes may include QuickTime +#include "../mov/tiio_mov.h" #include "tiio_3gp.h" +#include "movsettings.h" + namespace { int CompressionNoneId = 0; diff --git a/toonz/sources/image/CMakeLists.txt b/toonz/sources/image/CMakeLists.txt index 87953ce..720af0e 100644 --- a/toonz/sources/image/CMakeLists.txt +++ b/toonz/sources/image/CMakeLists.txt @@ -26,6 +26,7 @@ set(HEADERS mesh/tiio_mesh.h exr/tinyexr_otmod.h exr/tiio_exr.h + tzm/tiio_tzm.h ) set(SOURCES @@ -56,6 +57,7 @@ set(SOURCES sprite/tiio_sprite.cpp mesh/tiio_mesh.cpp exr/tiio_exr.cpp + tzm/tiio_tzm.cpp ) diff --git a/toonz/sources/image/ffmpeg/tiio_ffmpeg.cpp b/toonz/sources/image/ffmpeg/tiio_ffmpeg.cpp index b4f6f05..fe772ca 100644 --- a/toonz/sources/image/ffmpeg/tiio_ffmpeg.cpp +++ b/toonz/sources/image/ffmpeg/tiio_ffmpeg.cpp @@ -1,5 +1,7 @@ +#include "toonz/preferences.h" +#include "toonz/toonzfolders.h" + #include "tiio_ffmpeg.h" -#include "../toonz/tapp.h" #include "tsystem.h" #include "tsound.h" #include "timageinfo.h" @@ -11,8 +13,6 @@ #include #include #include -#include "toonz/preferences.h" -#include "toonz/toonzfolders.h" #include "tmsgcore.h" #include "thirdparty.h" diff --git a/toonz/sources/image/mov/tiio_mov.h b/toonz/sources/image/mov/tiio_mov.h index 37990f6..592f70a 100644 --- a/toonz/sources/image/mov/tiio_mov.h +++ b/toonz/sources/image/mov/tiio_mov.h @@ -7,6 +7,11 @@ #include "tiio_mov_proxy.h" #else +// Toonz includes +#include "tlevel_io.h" +#include "tthreadmessage.h" +#include "tcommon.h" + // Windows include #include @@ -40,11 +45,6 @@ namespace QuickTime { #include "tquicktime.h" } // namespace QuickTime -// Toonz includes -#include "tlevel_io.h" -#include "tthreadmessage.h" -#include "tcommon.h" - #undef DVAPI #undef DVVAR #ifdef IMAGE_EXPORTS diff --git a/toonz/sources/image/mov/tiio_movM.cpp b/toonz/sources/image/mov/tiio_movM.cpp index fe0ae20..beb338b 100644 --- a/toonz/sources/image/mov/tiio_movM.cpp +++ b/toonz/sources/image/mov/tiio_movM.cpp @@ -13,9 +13,14 @@ #include "tmachine.h" #include "tsystem.h" -#include "movsettings.h" +// movesettings deps, must be included before QuickTime includes +#include "texception.h" +#include "tpropertytype.h" +#include "tproperty.h" +// following includes may include QuickTime #include "tiio_movM.h" +#include "movsettings.h" /* QuickDraw は 10.7 以降なくなった */ //#define HAS_QUICKDRAW diff --git a/toonz/sources/image/mov/tiio_movM.h b/toonz/sources/image/mov/tiio_movM.h index e57aabd..0e0681d 100644 --- a/toonz/sources/image/mov/tiio_movM.h +++ b/toonz/sources/image/mov/tiio_movM.h @@ -7,6 +7,11 @@ #include "tiio_mov_proxy.h" #else +#include "tlevel_io.h" +#include "tthread.h" +#include "tthreadmessage.h" +#include "tquicktime.h" + //#include //#include //#include @@ -14,11 +19,6 @@ #include -#include "tquicktime.h" -#include "tlevel_io.h" -#include "tthread.h" -#include "tthreadmessage.h" - bool IsQuickTimeInstalled(); class TLevelWriterMov : public TLevelWriter { diff --git a/toonz/sources/image/mov/tiio_movW.cpp b/toonz/sources/image/mov/tiio_movW.cpp index a01a765..7bcbb43 100644 --- a/toonz/sources/image/mov/tiio_movW.cpp +++ b/toonz/sources/image/mov/tiio_movW.cpp @@ -11,6 +11,12 @@ #include "../avi/tiio_avi.h" #include "trasterimage.h" +// movesettings deps, must be included before QuickTime includes +#include "texception.h" +#include "tpropertytype.h" +#include "tproperty.h" + +// following includes may include QuickTime #include "tiio_mov.h" #include "movsettings.h" diff --git a/toonz/sources/image/sprite/tiio_sprite.cpp b/toonz/sources/image/sprite/tiio_sprite.cpp index 353fc9c..02e2d90 100644 --- a/toonz/sources/image/sprite/tiio_sprite.cpp +++ b/toonz/sources/image/sprite/tiio_sprite.cpp @@ -1,6 +1,5 @@ #include "tiio_sprite.h" -#include "../toonz/tapp.h" #include "tsystem.h" #include "tsound.h" @@ -324,4 +323,4 @@ void Tiio::SpriteWriterProperties::updateTranslation() { } // Tiio::Reader* Tiio::makeSpriteReader(){ return nullptr; } -// Tiio::Writer* Tiio::makeSpriteWriter(){ return nullptr; } \ No newline at end of file +// Tiio::Writer* Tiio::makeSpriteWriter(){ return nullptr; } diff --git a/toonz/sources/image/tiio.cpp b/toonz/sources/image/tiio.cpp index 97d766e..be16eca 100644 --- a/toonz/sources/image/tiio.cpp +++ b/toonz/sources/image/tiio.cpp @@ -18,9 +18,40 @@ // why (it would be included anyway though) #include +// Common includes +#include "./quantel/tiio_quantel.h" +#include "./sgi/tiio_sgi.h" +#include "./tga/tiio_tga.h" +#include "./png/tiio_png.h" +/* Can't build this on FreeBSD: libtiff requires internal API access. + * Probably some one get luck to fix this. */ +#ifndef FREEBSD +#include "./tif/tiio_tif.h" +#include "./tzp/tiio_tzp.h" +#include "./tzp/tiio_plt.h" +#endif +#include "./psd/tiio_psd.h" +#include "./avi/tiio_avi.h" +#include "./pli/tiio_pli.h" +#include "./tzl/tiio_tzl.h" +#include "./tzm/tiio_tzm.h" +#include "./svg/tiio_svg.h" +#include "./ffmpeg/tiio_gif.h" +#include "./ffmpeg/tiio_webm.h" +#include "./ffmpeg/tiio_mp4.h" +#include "./ffmpeg/tiio_apng.h" +#include "./ffmpeg/tiio_ff_mov.h" +#include "./mesh/tiio_mesh.h" +#include "./sprite/tiio_sprite.h" +#include "./exr/tiio_exr.h" + // Platform-specific includes #if defined(_WIN32) +#include "./zcc/tiio_zcc.h" +#include "./mov/tiio_mov.h" +#include "./3gp/tiio_3gp.h" + #if !defined(x64) && !defined(__GNUC__) #define list QuickTime_list @@ -46,10 +77,6 @@ #endif -#include "./mov/tiio_mov.h" -#include "./3gp/tiio_3gp.h" -#include "./zcc/tiio_zcc.h" - #elif defined(MACOSX) #include "./mov/tiio_movM.h" #include "./3gp/tiio_3gpM.h" @@ -60,32 +87,6 @@ #include "./3gp/tiio_3gp_proxy.h" #endif -// Common includes -#include "./quantel/tiio_quantel.h" -#include "./sgi/tiio_sgi.h" -#include "./tga/tiio_tga.h" -#include "./png/tiio_png.h" -/* Can't build this on FreeBSD: libtiff requires internal API access. - * Probably some one get luck to fix this. */ -#ifndef FREEBSD -#include "./tif/tiio_tif.h" -#include "./tzp/tiio_tzp.h" -#include "./tzp/tiio_plt.h" -#endif -#include "./psd/tiio_psd.h" -#include "./avi/tiio_avi.h" -#include "./pli/tiio_pli.h" -#include "./tzl/tiio_tzl.h" -#include "./svg/tiio_svg.h" -#include "./ffmpeg/tiio_gif.h" -#include "./ffmpeg/tiio_webm.h" -#include "./ffmpeg/tiio_mp4.h" -#include "./ffmpeg/tiio_apng.h" -#include "./ffmpeg/tiio_ff_mov.h" -#include "./mesh/tiio_mesh.h" -#include "./sprite/tiio_sprite.h" -#include "./exr/tiio_exr.h" - //------------------------------------------------------------------- // static TPluginInfo info("imageIOPlugin"); @@ -141,6 +142,9 @@ void initImageIo(bool lightVersion) { TLevelReader::define("mesh", TLevelReaderMesh::create); TFileType::declare("mesh", TFileType::MESH_IMAGE); + TLevelWriter::define("tzm", tzm::createWriter, false); + TLevelReader::define("tzm", tzm::createReader); + TFileType::declare("tzm", TFileType::META_LEVEL); } // !lightversion TFileType::declare("tpl", TFileType::PALETTE_LEVEL); diff --git a/toonz/sources/image/tzm/tiio_tzm.cpp b/toonz/sources/image/tzm/tiio_tzm.cpp new file mode 100644 index 0000000..0435259 --- /dev/null +++ b/toonz/sources/image/tzm/tiio_tzm.cpp @@ -0,0 +1,191 @@ + +#include + +#include +#include +#include + +#include +#include + +#include "tiio_tzm.h" + + + +//=========================================================================== + +namespace { + class TLevelWriterTzm; + + class TImageWriterTzm final : public TImageWriter { + private: + TLevelWriterTzm &m_writer; + TFrameId m_frameId; + public: + TImageWriterTzm(const TFilePath &path, TLevelWriterTzm &writer, const TFrameId &frameId): + TImageWriter(path), m_writer(writer), m_frameId(frameId) { } + void save(const TImageP &image) override; + }; + + class TLevelWriterTzm final : public TLevelWriter { + private: + TVariant m_data; + Tofstream *m_stream; + + public: + TLevelWriterTzm(const TFilePath &path, TPropertyGroup *winfo): + TLevelWriter(path, winfo) + { + // lock file for whole time of saving process to avoid collisions + try { + m_stream = new Tofstream(path); + } catch (const std::exception &e) { + throw TImageException(path, e.what()); + } catch (const TException &e) { + throw TImageException(path, to_string(e.getMessage())); + } + + m_data["type"].setString("tzm"); + m_data["version"].setDouble( 0.0 ); + } + + TImageWriterP getFrameWriter(TFrameId frameId) override + { return TImageWriterP(new TImageWriterTzm(m_path, *this, frameId)); } + + void saveFrame(const TFrameId &frameId, const TImageP &image) { + if (const TMetaImage *metaImage = dynamic_cast(image.getPointer())) { + TMetaImage::Reader reader(*metaImage); + TVariant &frameData = m_data["frames"][frameId.expand()]; + TVariant &objectsData = frameData["objects"]; + objectsData.setType(TVariant::List); + for(TMetaObjectListCW::iterator i = reader->begin(); i != reader->end(); ++i) { + if (*i) { + TVariant &objectData = objectsData[ objectsData.size() ]; + objectData["type"].setString( (*i)->getTypeName() ); + objectData["data"] = (*i)->data(); + } + } + } + } + + ~TLevelWriterTzm() { + try { + m_data["creator"].setString( m_creator.toStdString() ); + m_data.toStream(*m_stream, true); + delete m_stream; + } catch (const std::exception &e) { + throw TImageException(m_path, e.what()); + } catch (const TException &e) { + throw TImageException(m_path, to_string(e.getMessage())); + } + } + }; + + void TImageWriterTzm::save(const TImageP &image) + { m_writer.saveFrame(m_frameId, image); } +} // end of anonymous namespace for TLevelWriterTzm + +//=========================================================================== + +namespace { + class TLevelReaderTzm; + + class TImageReaderTzm final : public TImageReader { + private: + TLevelReaderTzm &m_reader; + TFrameId m_frameId; + public: + TImageReaderTzm(const TFilePath &path, TLevelReaderTzm &reader, const TFrameId &frameId): + TImageReader(path), m_reader(reader), m_frameId(frameId) { } + TImageP load() override; + }; + + + class TLevelReaderTzm final : public TLevelReader { + private: + TVariant m_data; + TLevelP m_level; + + void warning(const std::string &msg) + { std::cerr << to_string(m_path.getWideString()) << ": " << msg << std::endl; } + + public: + TLevelReaderTzm(const TFilePath &path): + TLevelReader(path) { } + + TImageReaderP getFrameReader(TFrameId frameId) override + { return TImageReaderP(new TImageReaderTzm(m_path, *this, frameId)); } + + TLevelP loadInfo() override { + try { + Tifstream stream(m_path); + m_data.fromStream(stream); + } catch (const std::exception &e) { + throw TImageException(m_path, e.what()); + } catch (const TException &e) { + throw TImageException(m_path, to_string(e.getMessage())); + } + + if (m_data["type"].getString() != "tzm") + warning("seems it's not TZM"); + if (m_data["version"].getDouble() > 0.0 + TConsts::epsilon) + warning( "version (" + + std::to_string(m_data["version"].getDouble()) + + ") is higher than supported (0.0)"); + + const TVariantMap &map = m_data["frames"].getMap(); + for(TVariantMap::const_iterator i = map.begin(); i != map.end(); ++i) { + TFrameId frameId(i->first.str()); + if (frameId.getNumber() < 0) + warning("wrong frame number: " + i->first.str()); + else + if (m_level->getTable()->count(frameId)) + warning(frameId.expand()); + else + m_level->setFrame(frameId, TImageP()); + } + + return m_level; + } + + QString getCreator() override + { return QString::fromStdString( m_data["creator"].getString() ); } + + TImageP loadFrame(const TFrameId &frameId) { + const TVariantMap &map = m_data["frames"].getMap(); + for(TVariantMap::const_iterator i = map.begin(); i != map.end(); ++i) { + if (TFrameId(i->first.str()) == frameId) { + TMetaImage *image = new TMetaImage(); + TMetaImage::Writer writer(*image); + const TVariant &objectsData = i->second["objects"]; + if (objectsData.getType() == TVariant::List) { + for(int j = 0; j < objectsData.size(); ++j) { + const TVariant &objectData = objectsData[j]; + if (!objectData["type"].getString().empty()) { + TMetaObjectP obj( new TMetaObject(objectData["type"].getString()) ); + obj->data() = objectData["data"]; + writer->push_back(obj); + } + } + } + return image; + } + } + return TImageP(); + } + }; + + TImageP TImageReaderTzm::load() + { return m_reader.loadFrame(m_frameId); } +} // end of anonymous namespace for TLevelReaderTzm + +//=========================================================================== + +namespace tzm { + TLevelWriter* createWriter(const TFilePath &path, TPropertyGroup *winfo) + { return new TLevelWriterTzm(path, winfo); } + TLevelReader* createReader(const TFilePath &path) + { return new TLevelReaderTzm(path); } +} + +//============================================================================= diff --git a/toonz/sources/image/tzm/tiio_tzm.h b/toonz/sources/image/tzm/tiio_tzm.h new file mode 100644 index 0000000..07f9a61 --- /dev/null +++ b/toonz/sources/image/tzm/tiio_tzm.h @@ -0,0 +1,14 @@ +#pragma once + +#ifndef TTIO_TZM_INCLUDED +#define TTIO_TZM_INCLUDED + +#include + + +namespace tzm { + TLevelWriter* createWriter(const TFilePath &path, TPropertyGroup *winfo); + TLevelReader* createReader(const TFilePath &path); +} + +#endif // TTIO_TZM_INCLUDED diff --git a/toonz/sources/include/movsettings.h b/toonz/sources/include/movsettings.h index ad64de9..702a5ec 100644 --- a/toonz/sources/include/movsettings.h +++ b/toonz/sources/include/movsettings.h @@ -17,6 +17,10 @@ #ifdef _WIN32 +#include "texception.h" +#include "tpropertytype.h" +#include "tproperty.h" + #define list QuickTime_list #define map QuickTime_map #define iterator QuickTime_iterator @@ -44,12 +48,6 @@ #undef int_fast16_t #undef uint_fast16_t -#include "texception.h" -#include "tpropertytype.h" -//#include "timageinfo.h" -//#include "tlevel_io.h" -#include "tproperty.h" - #else // _WIN32 #define list List diff --git a/toonz/sources/include/tconstwrapper.h b/toonz/sources/include/tconstwrapper.h new file mode 100644 index 0000000..e105074 --- /dev/null +++ b/toonz/sources/include/tconstwrapper.h @@ -0,0 +1,167 @@ +#pragma once + +#ifndef TCONSTWRAPPER_INCLUDED +#define TCONSTWRAPPER_INCLUDED + +#include +#include +#include + +#include "tcommon.h" + +#undef DVAPI +#undef DVVAR +#ifdef TNZCORE_EXPORTS +#define DVAPI DV_EXPORT_API +#define DVVAR DV_EXPORT_VAR +#else +#define DVAPI DV_IMPORT_API +#define DVVAR DV_IMPORT_VAR +#endif + +//========================================================= + + +template +class TConstArrayWrapperT { +public: + typedef T value_type; + typedef TT src_value_type; + + class reverse_iterator; + + class iterator { + private: + const src_value_type *pointer; + friend class TConstArrayWrapperT; + friend class reverse_iterator; + + explicit iterator(const src_value_type *pointer): pointer(pointer) { } + public: + iterator(): pointer() { } + iterator(const iterator &other): pointer(other.pointer) { } + explicit iterator(const reverse_iterator &other): pointer(other.pointer) { } + + iterator& operator=(const iterator &other) const { pointer = other.pointer; return *this; } + + bool operator==(const iterator &other) const { return pointer == other.pointer; } + bool operator!=(const iterator &other) const { return pointer != other.pointer; } + bool operator< (const iterator &other) const { return pointer < other.pointer; } + bool operator> (const iterator &other) const { return pointer > other.pointer; } + bool operator<=(const iterator &other) const { return pointer <= other.pointer; } + bool operator>=(const iterator &other) const { return pointer >= other.pointer; } + ptrdiff_t operator-(const iterator &other) const { return pointer - other.pointer; } + iterator operator+(ptrdiff_t diff) const { return iterator(pointer + diff); } + iterator operator-(ptrdiff_t diff) const { return iterator(pointer - diff); } + + iterator& operator++() { ++pointer; return *this; } + iterator& operator--() { --pointer; return *this; } + iterator operator++(int) { ++pointer; return iterator(pointer-1); } + iterator operator--(int) { --pointer; return iterator(pointer+1); } + iterator operator+=(ptrdiff_t diff) { pointer += diff; return *this; } + iterator operator-=(ptrdiff_t diff) { pointer -= diff; return *this; } + + const value_type* operator->() const { assert(pointer); return cast(pointer); } + const value_type& operator*() const { assert(pointer); return *cast(pointer); } + }; + + class reverse_iterator { + private: + const src_value_type *pointer; + friend class TConstArrayWrapperT; + + explicit reverse_iterator(const src_value_type *pointer): pointer(pointer) { } + public: + reverse_iterator(): pointer() { } + reverse_iterator(const reverse_iterator &other): pointer(other.pointer) { } + explicit reverse_iterator(const iterator &other): pointer(other.pointer) { } + + reverse_iterator& operator=(const reverse_iterator &other) const { pointer = other.pointer; return *this; } + + bool operator==(const reverse_iterator &other) const { return pointer == other.pointer; } + bool operator!=(const reverse_iterator &other) const { return pointer != other.pointer; } + bool operator< (const reverse_iterator &other) const { return pointer > other.pointer; } + bool operator> (const reverse_iterator &other) const { return pointer < other.pointer; } + bool operator<=(const reverse_iterator &other) const { return pointer >= other.pointer; } + bool operator>=(const reverse_iterator &other) const { return pointer <= other.pointer; } + ptrdiff_t operator-(const reverse_iterator &other) const { return other.pointer - pointer; } + reverse_iterator operator+(ptrdiff_t diff) const { return reverse_iterator(pointer - diff); } + reverse_iterator operator-(ptrdiff_t diff) const { return reverse_iterator(pointer + diff); } + + reverse_iterator& operator++() { --pointer; return *this; } + reverse_iterator& operator--() { ++pointer; return *this; } + reverse_iterator operator++(int) { --pointer; return reverse_iterator(pointer+1); } + reverse_iterator operator--(int) { ++pointer; return reverse_iterator(pointer-1); } + reverse_iterator operator+=(ptrdiff_t diff) { pointer -= diff; return *this; } + reverse_iterator operator-=(ptrdiff_t diff) { pointer += diff; return *this; } + + const value_type* operator->() const { assert(pointer); return cast(pointer); } + const value_type& operator*() const { assert(pointer); return *cast(pointer); } + }; + +private: + const src_value_type *m_begin; + const src_value_type *m_end; + const src_value_type *m_rbegin; + const src_value_type *m_rend; + size_t m_size; + + static const value_type* cast(const src_value_type *pointer) + { return static_cast(pointer); } + +public: + TConstArrayWrapperT(): + m_begin(), m_end(), m_rbegin(), m_rend(), m_size() { } + TConstArrayWrapperT(const src_value_type *data, size_t size): + m_begin(), m_end(), m_rbegin(), m_rend(), m_size() { set(data, size); } + TConstArrayWrapperT(const TConstArrayWrapperT &other): + m_begin(), m_end(), m_rbegin(), m_rend(), m_size() { *this = other; } + explicit TConstArrayWrapperT(const std::vector &v): + m_begin(), m_end(), m_rbegin(), m_rend(), m_size() { set(v); } + + void reset() { + m_begin = 0; + m_end = 0; + m_rbegin = 0; + m_rend = 0; + m_size = 0; + } + + void set(const src_value_type *data, size_t size) { + assert((data != 0) == (size != 0)); + if (!data) reset(); + m_begin = data; + m_end = data + size; + m_rbegin = m_end - 1; + m_rend = m_begin - 1; + m_size = size; + } + + void set(const std::vector &v) + { if (v.empty()) reset(); else set(&v.front(), v.size()); } + + TConstArrayWrapperT& operator=(const TConstArrayWrapperT &other) + { set(other.m_begin, other.m_size); return *this; } + + size_t size() const { return m_size; } + bool empty() const { return m_size != 0; } + + iterator begin() const + { return iterator(m_begin); } + iterator end() const + { return iterator(m_end); } + reverse_iterator rbegin() const + { return reverse_iterator(m_rbegin); } + reverse_iterator rend() const + { return reverse_iterator(m_rend); } + const value_type& at (size_t index) const + { assert(index < m_size); return *cast(m_begin + index); } + const value_type& operator[] (size_t index) const + { return at(index); } + const value_type& front() const + { assert(!empty()); return *cast(m_begin); } + const value_type& back() const + { assert(!empty()); return *cast(m_rbegin); } +}; + +#endif diff --git a/toonz/sources/include/tfilepath.h b/toonz/sources/include/tfilepath.h index 4581863..b31e36b 100644 --- a/toonz/sources/include/tfilepath.h +++ b/toonz/sources/include/tfilepath.h @@ -57,6 +57,8 @@ public: } TFrameId(int f, QString str, int p = 4, char s = '.') : m_frame(f), m_letter(str), m_zeroPadding(p), m_startSeqInd(s) {} + explicit TFrameId(const std::string &str, char s = '.'); + explicit TFrameId(const std::wstring &wstr, char s = '.'); inline bool operator==(const TFrameId &f) const { return f.m_frame == m_frame && f.m_letter == m_letter; @@ -318,18 +320,6 @@ type is a string that indicate the filename extension(ex:. bmp or .bmp)*/ //----------------------------------------------------------------------------- -class TMalformedFrameException final : public TException { -public: - TMalformedFrameException(const TFilePath &fp, - const std::wstring &msg = std::wstring()) - : TException(fp.getWideName() + L":" + msg) {} - -private: - TMalformedFrameException(); -}; - -//----------------------------------------------------------------------------- - DVAPI std::ostream &operator<<(std::ostream &out, const TFilePath &path); typedef std::list TFilePathSet; diff --git a/toonz/sources/include/tfiletype.h b/toonz/sources/include/tfiletype.h index cc3d928..05cf3b2 100644 --- a/toonz/sources/include/tfiletype.h +++ b/toonz/sources/include/tfiletype.h @@ -41,6 +41,9 @@ enum Type { AUDIO_LEVEL = 0x20 | LEVEL, PALETTE_LEVEL = 0x40 | LEVEL, + META_IMAGE = 0x80, + META_LEVEL = META_IMAGE | LEVEL, + TABSCENE = 0x2000 | SCENE, TOONZSCENE = 0x4000 | SCENE, diff --git a/toonz/sources/include/tgeometry.h b/toonz/sources/include/tgeometry.h index bbcd801..7654e26 100644 --- a/toonz/sources/include/tgeometry.h +++ b/toonz/sources/include/tgeometry.h @@ -17,6 +17,17 @@ #endif //============================================================================= + +inline double logNormalDistribuitionUnscaled(double x, double x0, double w) + { return exp(-0.5*pow(log(x/x0)/w, 2.0))/x; } + +inline double logNormalDistribuition(double x, double x0, double w) + { return logNormalDistribuitionUnscaled(x, x0, w)/(w*sqrt(2.0*M_PI)); } + +//============================================================================= + +template class TPoint4T; + /* * This is an example of how to use the TPointT, the TRectT and the TAffine * classes. @@ -31,6 +42,8 @@ public: TPointT() : x(0), y(0){}; TPointT(T _x, T _y) : x(_x), y(_y){}; TPointT(const TPointT &point) : x(point.x), y(point.y){}; + explicit TPointT(const TPoint4T &point); + inline TPointT &operator=(const TPointT &a) { x = a.x; y = a.y; @@ -54,10 +67,27 @@ public: return TPointT(x - a.x, y - a.y); }; inline TPointT operator-() const { return TPointT(-x, -y); }; +}; - bool operator!=(const TPointT &p) const { return x != p.x || y != p.y; } +template +class TPoint4T { +public: + union { + struct { T x, y, z, w; }; + T a[4]; + }; + + TPoint4T(): + x(), y(), z(), w() { }; + TPoint4T(T x, T y, T z, T w): + x(x), y(y), z(z), w(w) { }; + explicit TPoint4T(const TPointT &p, T w = (T)1): + x(p.x), y(p.y), z(), w(w) { }; }; +template +inline TPointT::TPointT(const TPoint4T &point) : x(point.x), y(point.y){}; + /*! \relates TPointT * Rotate a point 90 degrees (counterclockwise). \param p a point. @@ -100,6 +130,7 @@ inline std::ostream &operator<<(std::ostream &out, const TPointT &p) { typedef TPointT TPoint, TPointI; typedef TPointT TPointD; +typedef TPoint4T TPoint4D; #ifdef _WIN32 template class DVAPI TPointT; @@ -110,6 +141,10 @@ template inline bool operator==(const TPointT &p0, const TPointT &p1) { return p0.x == p1.x && p0.y == p1.y; } +template +inline bool operator!=(const TPointT &p0, const TPointT &p1) { + return p0.x != p1.x || p0.y != p1.y; +} //----------------------------------------------------------------------------- @@ -190,6 +225,9 @@ inline double tdistance2(const TPointD &p1, const TPointD &p2) { inline bool operator==(const TPointD &p0, const TPointD &p1) { return tdistance2(p0, p1) < TConsts::epsilon * TConsts::epsilon; } +inline bool operator!=(const TPointD &p0, const TPointD &p1) { + return !(p0 == p1); +} /*! \relates TPointT @@ -887,6 +925,7 @@ public: , a21(a.a21) , a22(a.a22) , a23(a.a23){}; + /*! Assignment operator. */ @@ -1003,6 +1042,8 @@ a12*a12+a13*a13+a21*a21+a23*a23) < err; identity matrix. */ + bool isZero(double err = 1.e-8) const; + bool isTranslation(double err = 1.e-8) const; /*Sposto in tgeometry.cpp { @@ -1034,7 +1075,12 @@ return TPointD(p.x*a11+p.y*a12+a13, p.x*a21+p.y*a22+a23); */ /*! - Returns the transformed box of the bounding box. + Transform point without translation + */ + TPointD transformDirection(const TPointD &p) const; + + /*! + Retruns the transformed box of the bounding box. */ TRectD operator*(const TRectD &rect) const; @@ -1050,6 +1096,32 @@ return TPointD(p.x*a11+p.y*a12+a13, p.x*a21+p.y*a22+a23); See above. */ TAffine place(const TPointD &pIn, const TPointD &pOut) const; + + inline static TAffine identity() + { return TAffine(); } + inline static TAffine zero() + { return TAffine(0, 0, 0, 0, 0, 0); } + + inline static TAffine translation(double x, double y) + { return TAffine(1, 0, x, 0, 1, y); } + inline static TAffine translation(const TPointD &p) + { return translation(p.x, p.y); } + + inline static TAffine scale(double sx, double sy) + { return TAffine(sx, 0, 0, 0, sy, 0); } + inline static TAffine scale(double s) + { return scale(s, s); } + inline static TAffine scale(const TPointD ¢er, double sx, double sy) + { return translation(center)*scale(sx, sy)*translation(-center); } + inline static TAffine scale(const TPointD ¢er, double s) + { return scale(center, s, s); } + + static TAffine rotation(double angle); + inline static TAffine rotation(const TPointD ¢er, double angle) + { return translation(center)*rotation(angle)*translation(-center); } + + inline static TAffine shear(double sx, double sy) + { return TAffine(1, sx, 0, sy, 1, 0); } }; //----------------------------------------------------------------------------- @@ -1182,4 +1254,287 @@ inline std::ostream &operator<<(std::ostream &out, const TAffine &a) { << ", " << a.a22 << ", " << a.a23 << ")"; } + +//============================================================================= + +//! This class performs basic manipulations of affine transformations in 3D space. +//! the matrix is transposed to TAffine and equal to OpenGL + +class DVAPI TAffine4 { +public: + union { + struct { + double a11, a12, a13, a14; + double a21, a22, a23, a24; + double a31, a32, a33, a34; + double a41, a42, a43, a44; + }; + double m[4][4]; + double a[16]; + }; + + inline TAffine4(): + a11(1.0), a12(0.0), a13(0.0), a14(0.0), + a21(0.0), a22(1.0), a23(0.0), a24(0.0), + a31(0.0), a32(0.0), a33(1.0), a34(0.0), + a41(0.0), a42(0.0), a43(0.0), a44(1.0) { } + + inline explicit TAffine4(const TAffine &a): + a11(a.a11), a12(a.a21), a13(0.0), a14(0.0), + a21(a.a12), a22(a.a22), a23(0.0), a24(0.0), + a31( 0.0 ), a32( 0.0 ), a33(1.0), a34(0.0), + a41(a.a13), a42(a.a23), a43(0.0), a44(1.0) { } + + inline TAffine4( + const TPoint4D &rowX, + const TPoint4D &rowY, + const TPoint4D &rowZ, + const TPoint4D &rowW + ): + a11(rowX.x), a12(rowX.y), a13(rowX.z), a14(rowX.w), + a21(rowY.x), a22(rowY.y), a23(rowY.z), a24(rowY.w), + a31(rowZ.x), a32(rowZ.y), a33(rowZ.z), a34(rowZ.w), + a41(rowW.x), a42(rowW.y), a43(rowW.z), a44(rowW.w) { } + + inline TPoint4D& row(int index) + { return *(TPoint4D*)(m[index]); } + inline const TPoint4D& row(int index) const + { return *(const TPoint4D*)(m[index]); } + + inline TPoint4D& rowX() { return row(0); } + inline TPoint4D& rowY() { return row(1); } + inline TPoint4D& rowZ() { return row(2); } + inline TPoint4D& rowW() { return row(3); } + + inline const TPoint4D& rowX() const { return row(0); } + inline const TPoint4D& rowY() const { return row(1); } + inline const TPoint4D& rowZ() const { return row(2); } + inline const TPoint4D& rowW() const { return row(3); } + + TPoint4D operator*(const TPoint4D &b) const; + TAffine4 operator*(const TAffine4 &b) const; + TAffine4 operator*=(const TAffine4 &b); + + TAffine4 inv() const; + + TAffine get2d(double z = 0.0) const; + + inline static TAffine4 identity() { return TAffine4(); } + static TAffine4 translation(double x, double y, double z); + static TAffine4 scale(double x, double y, double z); + static TAffine4 rotation(double x, double y, double z, double angle); + static TAffine4 rotationX(double angle); + static TAffine4 rotationY(double angle); + static TAffine4 rotationZ(double angle); + static TAffine4 perspective(double near, double far, double tangent); +}; + + +//============================================================================= + +//! This class performs binary manipulations with angle ranges + +typedef unsigned int TAngleI; + +class DVAPI TAngleRangeSet { +public: + typedef TAngleI Type; + typedef std::vector List; + + static const Type min = Type(); + static const Type max = Type() - Type(1); + static const Type half = ((Type() - Type(1)) >> 1) + Type(1); + + static Type fromDouble(double a) + { return Type(round((a/M_2PI + 0.5)*max)); } + static double toDouble(Type a) + { return ((double)a/(double)max - 0.5)*M_2PI; } + static List::const_iterator empty_iterator() + { static List list; return list.end(); } + + struct Range { + Type a0, a1; + Range(): a0(), a1() { } + Range(Type a0, Type a1): a0(a0), a1(a1) { } + inline bool isEmpty() const { return a0 == a1; } + inline Range flip() const { return Range(a1, a0); } + }; + + struct Iterator { + private: + bool m_flip; + List::const_iterator m_prebegin; + List::const_iterator m_begin; + List::const_iterator m_end; + List::const_iterator m_current; + bool m_lapped; + + public: + inline Iterator(): m_flip(), m_lapped(true) + { reset(); } + inline explicit Iterator(const List &list, bool flip = false, bool reverse = false) + { set(list, flip, reverse); } + inline explicit Iterator(const TAngleRangeSet &ranges, bool flip = false, bool reverse = false) + { set(ranges, flip, reverse); } + + inline Iterator& set(bool full) { + m_flip = full; m_lapped = !m_flip; + m_current = m_prebegin = m_begin = m_end = empty_iterator(); + return *this; + } + + inline Iterator& reset() + { return set(false); } + + inline Iterator& set(const List &list, bool flip = false, bool reverse = false) { + assert(list.size()%2 == 0); + if (list.empty()) { + set(flip); + } else { + m_flip = flip; + m_lapped = false; + if (flip) { + m_prebegin = list.end() - 1; + m_begin = list.begin(); + m_end = m_prebegin - 1; + } else { + m_prebegin = list.begin(); + m_begin = m_prebegin + 1; + m_end = list.end() - 1; + } + } + m_current = reverse ? m_end : m_begin; + return *this; + } + + inline Iterator& set(const TAngleRangeSet &ranges, bool flip = false, bool reverse = false) + { return set(ranges.angles(), ranges.isFlipped() != flip, reverse); } + + inline const Type a0() const + { return valid() ? *(m_current == m_begin ? m_prebegin : m_current - 1) : Type(); } + inline const Type a1() const + { return valid() ? *m_current : Type(); } + inline double d0() const + { return toDouble(a0()); } + inline double d1() const + { return toDouble(a1()); } + inline double d1greater() const { + return !valid() ? (m_flip ? M_PI : -M_PI) + : m_current == m_begin && m_prebegin > m_begin + ? toDouble(*m_current) + M_2PI : toDouble(*m_current); + } + inline Range range() const + { return Range(a0(), a1()); } + inline int size() const + { return (m_end - m_begin)/2 + 1; } + inline int index() const + { return (m_current - m_begin)/2; } + inline int reverseIndex() const + { int i = index(); return i == 0 ? 0 : size() - i; } + inline bool lapped() const + { return m_lapped; } + inline bool valid() const + { return m_prebegin != m_begin; } + inline bool isFull() const + { return !valid() && m_flip; } + inline bool isEmpty() const + { return !valid() && !m_flip; } + + inline operator bool() const + { return !m_lapped; } + + inline Iterator& operator++() { + if (!valid()) { m_lapped = true; return *this; } + m_lapped = (m_current == m_end); + if (m_lapped) m_current = m_begin; else m_current += 2; + return *this; + } + + inline Iterator& operator--() { + if (!valid()) { m_lapped = true; return *this; } + m_lapped = (m_current == m_end); + if (m_lapped) m_current = m_end; else m_current -= 2; + return *this; + } + + inline Iterator& operator += (int i) { + if (i == 0) { m_lapped = isEmpty(); return *this; } + if (!valid()) { m_lapped = true; return *this; } + int ii = index(); + int s = size(); + if (ii + i >= 0 && ii + i < s) { + m_current += i*2; + m_lapped = false; + } else { + m_current = m_begin + ((ii + s + i%s)%s)*2; + m_lapped = true; + } + return *this; + } + + inline int operator-(const Iterator &i) const { + assert(m_flip == i.m_flip && m_begin == i.m_begin && m_end == i.m_end && m_prebegin == i.m_prebegin); + int ii = m_current - i.m_current; + return ii < 0 ? ii + size() : ii; + } + + inline Iterator operator++() const + { Iterator copy(*this); ++(*this); return copy; } + inline Iterator operator--() const + { Iterator copy(*this); --(*this); return copy; } + inline Iterator& operator -= (int i) + { return (*this) += -i; } + inline Iterator operator+(int i) const + { Iterator ii(*this); return ii += i; } + inline Iterator operator-(int i) const + { Iterator ii(*this); return ii -= i; } + }; + +private: + bool m_flip; + List m_angles; + + int find(Type a) const; + void insert(Type a); + void doAdd(Type a0, Type a1); + +public: + inline explicit TAngleRangeSet(bool fill = false): m_flip(fill) { } + inline TAngleRangeSet(const TAngleRangeSet &x, bool flip = false): + m_flip(x.isFlipped() != flip), m_angles(x.angles()) { } + + inline const List& angles() const { return m_angles; } + inline bool isFlipped() const { return m_flip; } + inline bool isEmpty() const { return !m_flip && m_angles.empty(); } + inline bool isFull() const { return m_flip && m_angles.empty(); } + + bool contains(Type a) const; + bool check() const; + + inline void clear() { m_flip = false; m_angles.clear(); } + inline void fill() { m_flip = true; m_angles.clear(); } + inline void invert() { m_flip = !m_flip; } + + void set(Type a0, Type a1); + void set(const TAngleRangeSet &x, bool flip = false); + + //! also known as 'xor' + void invert(Type a0, Type a1); + inline void invert(const Range &x) { invert(x.a0, x.a1); } + void invert(const TAngleRangeSet &x); + + void add(Type a0, Type a1); + inline void add(const Range &x) { add(x.a0, x.a1); } + void add(const TAngleRangeSet &x); + + void subtract(Type a0, Type a1); + inline void subtract(const Range &x) { subtract(x.a0, x.a1); } + void subtract(const TAngleRangeSet &x); + + void intersect(Type a0, Type a1); + inline void intersect(const Range &x) { intersect(x.a0, x.a1); } + void intersect(const TAngleRangeSet &x); +}; + + #endif // __T_GEOMETRY_INCLUDED__ diff --git a/toonz/sources/include/tgl.h b/toonz/sources/include/tgl.h index 5c993b1..134da8a 100644 --- a/toonz/sources/include/tgl.h +++ b/toonz/sources/include/tgl.h @@ -112,6 +112,9 @@ inline void tglColor(const TPixelD &p) { glColor4d(p.r, p.g, p.b, p.m); } //! retrieve the square of pixel size from current GL_MODELVIEW matrix DVAPI double tglGetPixelSize2(); +//! retrieve the current viewport bounds in world coordinates +DVAPI TRectD tglGetBounds(); + //! Draw text in string s at position p. DVAPI void tglDrawText(const TPointD &p, const std::string &s, @@ -181,6 +184,10 @@ inline void tglMultMatrix(const TAffine &aff) { glMultMatrixd(m); } +inline void tglMultMatrix(const TAffine4 &aff) { + glMultMatrixd(aff.a); +} + //============================================================================= void DVAPI tglRgbOnlyColorMask(); diff --git a/toonz/sources/include/timage.h b/toonz/sources/include/timage.h index f11660d..435f31b 100644 --- a/toonz/sources/include/timage.h +++ b/toonz/sources/include/timage.h @@ -49,7 +49,8 @@ lines, curves, and shapes or polygon(s), RASTER = 1, //!< A fullcolor raster image. VECTOR = 2, //!< A vector image. TOONZ_RASTER = 3, //!< A colormap raster image. - MESH = 4 //!< A textured mesh image. + MESH = 4, //!< A textured mesh image. + META = 5 //!< A non-painting data, GUI helpers, assistants, etc. }; /*! diff --git a/toonz/sources/include/tmetaimage.h b/toonz/sources/include/tmetaimage.h new file mode 100644 index 0000000..5726d1a --- /dev/null +++ b/toonz/sources/include/tmetaimage.h @@ -0,0 +1,254 @@ +#pragma once + +#ifndef TMETAIMAGE_INCLUDED +#define TMETAIMAGE_INCLUDED + +#include "timage.h" +#include "tthreadmessage.h" +#include "tsmartpointer.h" +#include "tvariant.h" +#include "tconstwrapper.h" + +#include +#include +#include +#include + +#include + +#undef DVAPI +#undef DVVAR +#ifdef TMETAIMAGE_EXPORTS +#define DVAPI DV_EXPORT_API +#define DVVAR DV_EXPORT_VAR +#else +#define DVAPI DV_IMPORT_API +#define DVVAR DV_IMPORT_VAR +#endif + +//------------------------------------------------------------------- + +class TMetaObject; +class TMetaObjectHandler; +typedef TSmartPointerT TMetaObjectP; //!< smart pointer to TMetaObject +typedef TMetaObjectP::Holder TMetaObjectH; //!< smart holder of TMetaObject +typedef TMetaObjectP::Const TMetaObjectPC; //!< smart pointer to constant TMetaObject +typedef std::vector TMetaObjectList; +typedef TConstArrayWrapperT TMetaObjectListCW; // TMetaObjectListConstWrapper + +//------------------------------------------------------------------- + +class DVAPI TMetaObjectType { +public: + const TStringId name; + + TMetaObjectType(const TStringId &name); + virtual ~TMetaObjectType(); + + void registerAlias(const TStringId &alias); + void unregisterAlias(const TStringId &alias); + + virtual TMetaObjectHandler* createHandler(TMetaObject &obj) const + { return 0; } + virtual QString getLocalName() const + { return QString::fromStdString(name.str()); } +}; + +//------------------------------------------------------------------- + +class DVAPI TMetaObject: public TSmartObject, public TVariantOwner { +public: + typedef TMetaObjectHandler* (*Fabric)(TMetaObject&); + typedef std::map Registry; + + struct LinkedList { + TMetaObject *first, *last; + LinkedList(): first(), last() { } + }; + typedef std::map LinkedMap; + typedef LinkedMap::iterator LinkedMapEntry; + +private: + LinkedMapEntry m_typeLink; + TMetaObject *m_previous, *m_next; + const TMetaObjectType *m_typeDesc; + TMetaObjectHandler *m_handler; + TVariant m_data; + + static Registry& registry(); + static LinkedMap& linkedMap(); + + static void rewrapAll(const TStringId &type); + void rewrap(const TStringId &type); + + void linkToType(const TStringId &type); + void unlinkFromType(); + + TMetaObject(const TMetaObject &other); + +public: + explicit TMetaObject(const TStringId &typeName = TStringId(), const TVariant &data = TVariant()); + explicit TMetaObject(const std::string &typeName, const TVariant &data = TVariant()); + ~TMetaObject(); + + void setType(const TStringId &name); + inline void setType(const std::string &name) + { setType(TStringId(name)); } + inline void resetType() + { setType(TStringId()); } + + inline const TMetaObjectType* getTypeDesc() const + { return m_typeDesc; } + inline const TStringId& getType() const + { return m_typeLink->first; } + inline const std::string& getTypeName() const + { return getType().str(); } + inline const TVariant& data() const + { return m_data; } + inline TVariant& data() + { return m_data; } + + void setDefaults(); + + template + const T* getHandler() const + { return dynamic_cast(m_handler); } + template + T* getHandler() + { return dynamic_cast(m_handler); } + + TMetaObjectHandler* handler() { return m_handler; } + const TMetaObjectHandler* handler() const { return m_handler; } + + void onVariantChanged(const TVariant &value) override; + + virtual TMetaObject* clone() const; + +public: + static const Registry& getRegistry() { return registry(); } + static void registerType(const TStringId &name, const TMetaObjectType &type); //!< register new or add alias + static void unregisterType(const TStringId &name); //!< unregister single alias + static void unregisterType(const TMetaObjectType &type); //!< unregister all aliases + static const TMetaObjectType* findType(const TStringId &name); +}; + +//------------------------------------------------------------------- + +class DVAPI TMetaObjectHandler { +protected: + class LockEvents { + public: + TMetaObjectHandler &owner; + explicit LockEvents(TMetaObjectHandler &owner): + owner(owner) { ++owner.m_locks; } + ~LockEvents() { --owner.m_locks; } + }; + +private: + TMetaObject &m_object; + const TMetaObjectType &m_typeDesc; + TAtomicVar m_locks; + +public: + TMetaObjectHandler(TMetaObject &object): + m_object(object), + m_typeDesc(*m_object.getTypeDesc()) + { assert(m_object.getTypeDesc()); } + virtual ~TMetaObjectHandler() { } + + inline const TMetaObjectType& getTypeDesc() const + { return m_typeDesc; } + inline const TStringId& getType() const + { return getTypeDesc().name; } + inline const std::string& getTypeName() const + { return getType().str(); } + inline const TMetaObject& object() const + { return m_object; } + inline TMetaObject& object() + { return m_object; } + inline const TStringId& getAlias() const + { return object().getType(); } + inline const std::string& getAliasName() const + { return getAlias().str(); } + inline const TVariant& data() const + { return object().data(); } + inline TVariant& data() + { return object().data(); } + +protected: + virtual void onSetDefaults() { } + virtual void onDataChanged(const TVariant &value) { } + virtual void onFixData() { } + +public: + void setDefaults() + { onSetDefaults(); } + void dataChanged(const TVariant &value) + { if (m_locks == 0) onDataChanged(value); } + void fixData() + { LockEvents lock(*this); onFixData(); } +}; + +//------------------------------------------------------------------- + +//! An image containing an assistants for painting. + +class DVAPI TMetaImage final : public TImage { +public: + class Reader: public QReadLocker { + private: + const TMetaImage &m_image; + const TMetaObjectListCW m_objects; + public: + Reader(const TMetaImage &image): + QReadLocker(&image.m_rwLock), + m_image(image), + m_objects(image.m_objects) { } + const TMetaImage& image() const + { return m_image; } + const TMetaObjectListCW& get() const + { return m_objects; } + const TMetaObjectListCW& operator*() const + { return get(); } + const TMetaObjectListCW* operator->() const + { return &get(); } + }; + + class Writer: public QWriteLocker { + private: + TMetaImage &m_image; + public: + Writer(TMetaImage &image): + QWriteLocker(&image.m_rwLock), m_image(image) { } + TMetaImage& image() const + { return m_image; } + TMetaObjectList& get() const + { return m_image.m_objects; } + TMetaObjectList& operator*() const + { return get(); } + TMetaObjectList* operator->() const + { return &get(); } + }; + +private: + mutable QReadWriteLock m_rwLock; + TMetaObjectList m_objects; + + TMetaImage(const TMetaImage &other); + + //! not implemented + TMetaImage &operator=(const TMetaImage &) { return *this; } + +public: + TMetaImage(); + ~TMetaImage(); + + //! Return the image type + TImage::Type getType() const override { return TImage::META; } + //! Return a clone of image + TImage* cloneImage() const override; + //! Return the bbox of the image + TRectD getBBox() const override; +}; + +#endif diff --git a/toonz/sources/include/tools/assistant.h b/toonz/sources/include/tools/assistant.h new file mode 100644 index 0000000..c2b2322 --- /dev/null +++ b/toonz/sources/include/tools/assistant.h @@ -0,0 +1,347 @@ +#pragma once + +#ifndef ASSISTANT_INCLUDED +#define ASSISTANT_INCLUDED + +// TnzTools includes +#include + +// TnzCore includes +#include +#include +#include +#include + +// Qt includes +#include + +// std includes +#include +#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 + + +//============================================================== + +// Forward declarations + +class TProperty; +class TPropertyGroup; + +class TToolViewer; +class TAssistant; +class TAssistantPoint; +class TGuideline; + +typedef TSmartPointerT TGuidelineP; +typedef std::vector TGuidelineList; +typedef std::map TAssistantPointMap; +typedef std::vector TAssistantPointOrder; + +//=================================================================== + + +//***************************************************************************************** +// TGuideline definition +//***************************************************************************************** + +class DVAPI TGuideline : public TSmartObject { +public: + const bool enabled; + const double magnetism; + + TGuideline(bool enabled, double magnetism): + enabled(enabled), magnetism(magnetism) { } + + virtual TTrackPoint transformPoint(const TTrackPoint &point) const + { return point; } + virtual void draw(bool active, bool enabled) const + { } + void draw(bool active = false) const + { draw(active, true); } + + TTrackPoint smoothTransformPoint(const TTrackPoint &point, double magnetism = 1.0) const { + return enabled + ? TTrack::interpolationLinear(point, transformPoint(point), magnetism*this->magnetism) + : point; + } + + void drawSegment( + const TPointD &p0, + const TPointD &p1, + double pixelSize, + bool active, + bool enabled = true) const; + + double calcTrackWeight(const TTrack &track, const TAffine &toScreen, bool &outLongEnough) const; + static TGuidelineP findBest(const TGuidelineList &guidelines, const TTrack &track, const TAffine &toScreen, bool &outLongEnough); +}; + + +//***************************************************************************************** +// TAssistantPoint definition +//***************************************************************************************** + +class DVAPI TAssistantPoint { +public: + enum Type { + Circle, + CircleFill, + CircleCross, + CircleDots, + CircleDoubleDots, + }; + + const TStringId name; + const TPointD defPosition; + + Type type; + TPointD position; + double radius; + bool visible; + + mutable bool selected; + + explicit TAssistantPoint(const TStringId &name, const TPointD &defPosition = TPointD()); +}; + + +//***************************************************************************************** +// TAssistantType definition +//***************************************************************************************** + +class DVAPI TAssistantType: public TMetaObjectType { +public: + TAssistantType(const TStringId &name): + TMetaObjectType(name) { } + TMetaObjectHandler* createHandler(TMetaObject &obj) const override; + virtual TAssistant* createAssistant(TMetaObject &obj) const + { return 0; } +}; + + +//***************************************************************************************** +// TAssistantTypeT definition +//***************************************************************************************** + +template +class TAssistantTypeT: public TAssistantType { +public: + typedef T Type; + + explicit TAssistantTypeT( + const TStringId &name, + const TStringId &alias1 = TStringId(), + const TStringId &alias2 = TStringId(), + const TStringId &alias3 = TStringId(), + const TStringId &alias4 = TStringId(), + const TStringId &alias5 = TStringId() + ): + TAssistantType(TStringId(name)) + { + if (alias1) registerAlias(alias1); + if (alias2) registerAlias(alias2); + if (alias3) registerAlias(alias3); + if (alias4) registerAlias(alias4); + if (alias5) registerAlias(alias5); + } + + explicit TAssistantTypeT( + const std::string &name, + const std::string &alias1 = std::string(), + const std::string &alias2 = std::string(), + const std::string &alias3 = std::string(), + const std::string &alias4 = std::string(), + const std::string &alias5 = std::string() + ): + TAssistantType(TStringId(name)) + { + if (!alias1.empty()) registerAlias(TStringId(alias1)); + if (!alias2.empty()) registerAlias(TStringId(alias2)); + if (!alias3.empty()) registerAlias(TStringId(alias3)); + if (!alias4.empty()) registerAlias(TStringId(alias4)); + if (!alias5.empty()) registerAlias(TStringId(alias5)); + } + + TAssistant* createAssistant(TMetaObject &obj) const override + { return new Type(obj); } + QString getLocalName() const override { + QString localName = Type::getLocalName(); + return localName.isEmpty() ? QString::fromStdString(name.str()) : localName; + } +}; + + +//***************************************************************************************** +// TAssistant definition +//***************************************************************************************** + +class DVAPI TAssistant : public TMetaObjectHandler { + Q_DECLARE_TR_FUNCTIONS(TAssistant) +protected: + const TStringId m_idEnabled; + const TStringId m_idPoints; + const TStringId m_idX; + const TStringId m_idY; + const TStringId m_idMagnetism; + + TAssistantPointMap m_points; + TAssistantPointOrder m_pointsOrder; + TAssistantPoint* m_basePoint; + + mutable TPropertyGroup m_properties; + +public: + TAssistant(TMetaObject &object); + + static QString getLocalName() + { return QString(); } + + inline const TAssistantPointMap& points() const + { return m_points; } + inline const TAssistantPointOrder& pointsOrder() const + { return m_pointsOrder; } + + inline const TAssistantPoint* findPoint(const TStringId &name) const { + TAssistantPointMap::const_iterator i = points().find(name); + return i == points().end() ? 0 : &i->second; + } + + void fixPoints(); + bool move(const TPointD &position); + bool movePoint(const TStringId &name, const TPointD &position); + void setPointSelection(const TStringId &name, bool selected) const; + void setAllPointsSelection(bool selected) const; + + bool getEnabled() const + { return data()[m_idEnabled].getBool(); } + void setEnabled(bool x) + { if (getEnabled() != x) data()[m_idEnabled].setBool(x); } + + double getMagnetism() const + { return data()[m_idMagnetism].getDouble(); } + void setMagnetism(double x) + { if (getMagnetism() != x) data()[m_idMagnetism].setDouble(x); } + + inline void selectPoint(const TStringId &name) const + { setPointSelection(name, true); } + inline void deselectPoint(const TStringId &name) const + { setPointSelection(name, false); } + inline void selectAll() const + { setAllPointsSelection(true); } + inline void deselectAll() const + { setAllPointsSelection(false); } + + TPropertyGroup& getProperties() const + { return m_properties; } + void propertyChanged(const TStringId &name) + { onPropertyChanged(name); } + + const TAssistantPoint& getBasePoint() const; + +protected: + TAssistantPoint& addPoint( + const TStringId &name, + TAssistantPoint::Type type, + const TPointD &defPosition, + bool visible, + double radius ); + + TAssistantPoint& addPoint( + const TStringId &name, + TAssistantPoint::Type type = TAssistantPoint::Circle, + const TPointD &defPosition = TPointD(), + bool visible = true ); + + inline TAssistantPoint& addPoint( + const std::string &name, + TAssistantPoint::Type type, + const TPointD &defPosition, + bool visible, + double radius ) + { return addPoint(TStringId(name), type, defPosition, visible, radius); } + + inline TAssistantPoint& addPoint( + const std::string &name, + TAssistantPoint::Type type = TAssistantPoint::Circle, + const TPointD &defPosition = TPointD(), + bool visible = true ) + { return addPoint(TStringId(name), type, defPosition, visible); } + + //! usually called when meta-object created + void onSetDefaults() override; + //! called when part of variant data changed + void onDataChanged(const TVariant &value) override; + //! called when field of root struct of variant data changed + virtual void onDataFieldChanged(const TStringId &name, const TVariant &value); + //! load object data from variant + virtual void onAllDataChanged(); + //! fix positions of all points (as like as all points moved) + virtual void onFixPoints(); + //! try to move point + virtual void onMovePoint(TAssistantPoint &point, const TPointD &position); + //! save object data to variant + virtual void onFixData(); + //! load all properties from variant + virtual void updateProperties(); + //! load single property from variant + virtual void updateProperty(const TStringId &name, const TVariant &value); + //! put value from property to variant + virtual void onPropertyChanged(const TStringId &name); + + double getDrawingAlpha(bool enabled = true) const; + double getDrawingGridAlpha() const; + + void drawSegment(const TPointD &p0, const TPointD &p1, double pixelSize, double alpha) const; + void drawDot(const TPointD &p, double alpha) const; + void drawPoint(const TAssistantPoint &point, double pixelSize) const; + + inline void drawSegment(const TPointD &p0, const TPointD &p1, double pixelSize) const + { drawSegment(p0, p1, pixelSize, getDrawingAlpha()); } + inline void drawDot(const TPointD &p) const + { drawDot(p, getDrawingAlpha()); } + + void addProperty(TProperty *p); + void setTranslation(const TStringId &name, const QString &localName) const; + +public: + virtual void updateTranslation() const; + virtual void getGuidelines(const TPointD &position, const TAffine &toTool, TGuidelineList &outGuidelines) const; + virtual void draw(TToolViewer *viewer, bool enabled) const; + void draw(TToolViewer *viewer) const { draw(viewer, true); } + virtual void drawEdit(TToolViewer *viewer) const; + + static bool calcPerspectiveStep( + double minStep, + double minX, + double maxX, + double x0, + double x1, + double x2, + double &outK, + double &outMin, + double &outMax ); +}; + + +//***************************************************************************************** +// export template implementations for win32 +//***************************************************************************************** + +#ifdef _WIN32 +template class DVAPI TSmartPointerT; +#endif + + +#endif diff --git a/toonz/sources/include/tools/assistants/guidelineellipse.h b/toonz/sources/include/tools/assistants/guidelineellipse.h new file mode 100644 index 0000000..c8b1607 --- /dev/null +++ b/toonz/sources/include/tools/assistants/guidelineellipse.h @@ -0,0 +1,55 @@ +#pragma once + +#ifndef GUIDELINEELLIPSE_INCLUDED +#define GUIDELINEELLIPSE_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 + + +//============================================================== + +//***************************************************************************************** +// TGuidelineEllipse definition +//***************************************************************************************** + +class DVAPI TGuidelineEllipse : public TGuideline { +public: + const TAffine matrix; + const TAffine matrixInv; + + TGuidelineEllipse( + bool enabled, + double magnetism, + TAffine matrix ); + + TGuidelineEllipse( + bool enabled, + double magnetism, + TAffine matrix, + TAffine matrixInv ); + + //! returns false when ellipse is invisible + static bool truncateEllipse( + TAngleRangeSet &ranges, + const TAffine &ellipseMatrixInv, + const TRectD &bounds ); + + static int calcSegmentsCount(const TAffine &ellipseMatrix, double pixelSize); + + TTrackPoint transformPoint(const TTrackPoint &point) const override; + void draw(bool active, bool enabled) const override; +}; + +#endif diff --git a/toonz/sources/include/tools/assistants/guidelineline.h b/toonz/sources/include/tools/assistants/guidelineline.h new file mode 100644 index 0000000..7373be9 --- /dev/null +++ b/toonz/sources/include/tools/assistants/guidelineline.h @@ -0,0 +1,83 @@ +#pragma once + +#ifndef GUIDELINELINE_INCLUDED +#define GUIDELINELINE_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 + + +//============================================================== + +//***************************************************************************************** +// TGuidelineLineBase definition +//***************************************************************************************** + +class DVAPI TGuidelineLineBase : public TGuideline { +public: + const TPointD p0; + const TPointD p1; + + TGuidelineLineBase(bool enabled, double magnetism, const TPointD &p0, const TPointD &p1); + void drawLine(const TPointD &p0, const TPointD &p1, bool restrict0, bool restrict1, bool active, bool enabled) const; + static TPointD calcDirection(const TPointD &p0, const TPointD &p1); + static bool truncateInfiniteLine(const TRectD &bounds, TPointD &p0, TPointD &p1); + static bool truncateRay(const TRectD &bounds, TPointD &p0, TPointD &p1); + static bool truncateLine(const TRectD &bounds, TPointD &p0, TPointD &p1); +}; + + +//***************************************************************************************** +// TGuidelineLine definition +//***************************************************************************************** + +class DVAPI TGuidelineLine : public TGuidelineLineBase { +public: + const TPointD dir; + const double dist; + + TGuidelineLine(bool enabled, double magnetism, const TPointD &p0, const TPointD &p1); + TTrackPoint transformPoint(const TTrackPoint &point) const override; + void draw(bool active, bool enabled) const override; +}; + + +//***************************************************************************************** +// TGuidelineInfiniteLine definition +//***************************************************************************************** + +class DVAPI TGuidelineInfiniteLine : public TGuidelineLineBase { +public: + const TPointD dir; + + TGuidelineInfiniteLine(bool enabled, double magnetism, const TPointD &p0, const TPointD &p1); + TTrackPoint transformPoint(const TTrackPoint &point) const override; + void draw(bool active, bool enabled) const override; +}; + + +//***************************************************************************************** +// TGuidelineRay definition +//***************************************************************************************** + +class DVAPI TGuidelineRay : public TGuidelineLineBase { +public: + const TPointD dir; + + TGuidelineRay(bool enabled, double magnetism, const TPointD &p0, const TPointD &p1); + TTrackPoint transformPoint(const TTrackPoint &point) const override; + void draw(bool active, bool enabled) const override; +}; + +#endif diff --git a/toonz/sources/include/tools/inputmanager.h b/toonz/sources/include/tools/inputmanager.h new file mode 100644 index 0000000..7d9a58d --- /dev/null +++ b/toonz/sources/include/tools/inputmanager.h @@ -0,0 +1,398 @@ +#pragma once + +#ifndef INPUTMANAGER_INCLUDED +#define INPUTMANAGER_INCLUDED + +// TnzTools includes +#include +#include +#include + +// TnzCore includes +#include +#include +#include + +// Qt includes +#include +#include + +// std 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 + + +//==================================================== + +// Forward declarations + +class TTool; +class TInputModifier; +class TInputManager; + +typedef TSmartPointerT TInputModifierP; + +//=================================================================== + + +//***************************************************************************************** +// TInputSavePoint definition +//***************************************************************************************** + +class DVAPI TInputSavePoint { +public: + class DVAPI Holder { + private: + TInputSavePoint *m_savePoint; + bool m_lock = false; + + public: + inline explicit Holder(TInputSavePoint *savePoint = NULL, bool lock = true): + m_savePoint(), m_lock() + { set(savePoint, lock); } + inline Holder(const Holder &other): + m_savePoint(), m_lock() + { *this = other; } + inline ~Holder() + { reset(); } + + 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) { + if (m_lock) m_savePoint->unlock(); + m_savePoint->release(); + } + m_savePoint = savePoint; + m_lock = lock; + if (m_savePoint) { + m_savePoint->hold(); + if (m_lock) savePoint->lock(); + } + } else + if (m_lock != lock) { + if (m_savePoint) { + if (lock) m_savePoint->lock(); + else m_savePoint->unlock(); + } + m_lock = lock; + } + } + + inline void reset() + { set(NULL, false); } + inline void setLock(bool lock) + { set(m_savePoint, lock); } + inline void lock() + { setLock(true); } + inline void unlock() + { setLock(false); } + + 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 + { return m_savePoint && m_savePoint->available; } + inline bool isFree() const + { return !m_savePoint || m_savePoint->isFree(); } + }; + + typedef std::vector List; + +private: + int m_refCount; + int m_lockCount; + + inline void hold() + { ++m_refCount; } + inline void release() + { if ((--m_refCount) <= 0) delete this; } + inline void lock() + { ++m_lockCount; } + inline void unlock() + { --m_lockCount; } + +public: + bool available; + + inline explicit TInputSavePoint(bool available = false): + m_refCount(), m_lockCount(), available(available) { } + inline bool isFree() const + { return m_lockCount <= 0; } + + static inline Holder create(bool available = false) + { return Holder(new TInputSavePoint(available)); } +}; + + +//***************************************************************************************** +// TInputModifier definition +//***************************************************************************************** + +class DVAPI TInputModifier: public TSmartObject { +private: + TInputManager *m_manager; + +public: + typedef std::vector List; + + TInputManager* getManager() const + { return m_manager; } + void setManager(TInputManager *manager); + virtual void onSetManager() { } + + virtual void activate() { } + + virtual void modifyTrack( + const TTrack &track, + const TInputSavePoint::Holder &savePoint, + TTrackList &outTracks ); + virtual void modifyTracks( + const TTrackList &tracks, + const TInputSavePoint::Holder &savePoint, + TTrackList &outTracks ); + + virtual void modifyHover( + const TPointD &hover, + THoverList &outHovers ); + virtual void modifyHovers( + const THoverList &hovers, + THoverList &outHovers ); + + virtual TRectD calcDrawBoundsHover(const TPointD &hover) { return TRectD(); } + virtual TRectD calcDrawBoundsTrack(const TTrack &track) { return TRectD(); } + virtual TRectD calcDrawBounds(const TTrackList &tracks, const THoverList &hovers); + + virtual void drawTrack(const TTrack &track) { } + virtual void drawHover(const TPointD &hover) { } + virtual void drawTracks(const TTrackList &tracks); + virtual void drawHovers(const THoverList &hovers); + virtual void draw(const TTrackList &tracks, const THoverList &hovers); + + virtual void deactivate() { } +}; + + +//***************************************************************************************** +// TInputHandler definition +//***************************************************************************************** + +class TInputHandler { +public: + virtual void inputLeftButtonDown(const TTrackPoint&, const TTrack&) { } + virtual void inputLeftButtonDrag(const TTrackPoint&, const TTrack&) { } + virtual void inputLeftButtonUp(const TTrackPoint&, const TTrack&) { } + virtual void inputMouseMove(const TPointD&, const TInputState&) { } + virtual void inputRightButtonDown(const TPointD&, const TInputState&) { } + virtual bool inputKeyDown(QKeyEvent *) { return false; } + + virtual void inputSetBusy(bool) { } + + virtual bool inputKeyEvent( + bool press, + TInputState::Key key, + QKeyEvent *event, + const TInputManager &manager ); + + virtual void inputButtonEvent( + bool press, + TInputState::DeviceId device, + TInputState::Button button, + const TInputManager &manager ); + + virtual void inputHoverEvent(const TInputManager &manager); + + /*! paint single track-point at the top painting level */ + virtual void inputPaintTrackPoint(const TTrackPoint &point, const TTrack &track, bool firstTrack); + + /*! create new painting level and return true, or do nothing and return false + was: ------O-------O------ + become: ------O-------O------O */ + virtual bool inputPaintPush() { return false; } + /*! paint several track-points at the top painting level + was: ------O-------O------ + become: ------O-------O------------ */ + virtual void inputPaintTracks(const TTrackList &tracks); + /*! try to merge N top painting levels and return count of levels that actually merged + was: ------O-------O------O------ + become (N = 2): ------O--------------------- */ + virtual int inputPaintApply(int count) { return 0; } + /*! reset top level to initial state + was: ------O-------O------O------ + become: ------O-------O------O */ + virtual void inputPaintCancel() { } + /*! cancel and pop N painting levels + was: ------O-------O------O------ + become (N = 2): ------O------- */ + virtual void inputPaintPop(int count) { } + + virtual void inputInvalidateRect(const TRectD &bounds) { } + + virtual TTool* inputGetTool() { return nullptr; }; +}; + + +//***************************************************************************************** +// TInputManager definition +//***************************************************************************************** + +class DVAPI TInputManager { +public: + class TrackHandler: public TTrackHandler { + public: + std::vector saves; + TrackHandler(TTrack &original, int keysCount = 0): + TTrackHandler(original), saves(keysCount, 0) + { } + }; + +private: + TTimerTicks m_lastTicks; + TInputHandler *m_handler; + TInputModifier::List m_modifiers; + std::vector m_tracks; + std::vector m_hovers; + TInputSavePoint::List m_savePoints; + TRectD m_prevBounds; + TRectD m_nextBounds; + bool m_started; + int m_savePointsSent; + + static TInputState::TouchId m_lastTouchId; + + +public: + TInputState state; + bool drawPreview; + + +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(); + + int trackCompare( + const TTrack &track, + TInputState::DeviceId deviceId, + TInputState::TouchId touchId ) const; + const TTrackP& createTrack( + int index, + TInputState::DeviceId deviceId, + TInputState::TouchId touchId, + TTimerTicks ticks, + bool hasPressure, + bool hasTilt ); + const TTrackP& getTrack( + TInputState::DeviceId deviceId, + TInputState::TouchId touchId, + TTimerTicks ticks, + bool hasPressure, + bool hasTilt ); + void addTrackPoint( + const TTrackP& track, + const TPointD &position, + double pressure, + const TPointD &tilt, + double time, + bool final ); + void touchTracks(bool finish = false); + + void modifierActivate(const TInputModifierP &modifier); + void modifierDeactivate(const TInputModifierP &modifier); + +public: + inline const TTrackList& getInputTracks() const + { return m_tracks.front(); } + inline const TTrackList& getOutputTracks() const + { return m_tracks.back(); } + + inline const THoverList& getInputHovers() const + { return m_hovers.front(); } + inline const THoverList& getOutputHovers() const + { return m_hovers.back(); } + + void processTracks(); + void finishTracks(); + void reset(); + + TInputHandler* getHandler() const + { return m_handler; } + void setHandler(TInputHandler *handler); + + int getModifiersCount() const + { return (int)m_modifiers.size(); } + const TInputModifierP& getModifier(int index) const + { return m_modifiers[index]; } + int findModifier(const TInputModifierP &modifier) const; + void insertModifier(int index, const TInputModifierP &modifier); + void addModifier(const TInputModifierP &modifier) + { insertModifier(getModifiersCount(), modifier); } + void removeModifier(int index); + void removeModifier(const TInputModifierP &modifier) + { removeModifier(findModifier(modifier)); } + void clearModifiers(); + + void trackEvent( + TInputState::DeviceId deviceId, + TInputState::TouchId touchId, + const TPointD &position, + const double *pressure, + const TPointD *tilt, + bool final, + TTimerTicks ticks ); + bool keyEvent( + bool press, + TInputState::Key key, + TTimerTicks ticks, + QKeyEvent *event ); + void buttonEvent( + bool press, + TInputState::DeviceId deviceId, + TInputState::Button button, + TTimerTicks ticks); + void hoverEvent(const THoverList &hovers); + + TRectD calcDrawBounds(); + void draw(); + + static TInputState::TouchId genTouchId(); +}; + + +//***************************************************************************************** +// export template implementations for win32 +//***************************************************************************************** + +#ifdef _WIN32 +template class DVAPI TSmartPointerT; +#endif + + +#endif diff --git a/toonz/sources/include/tools/inputstate.h b/toonz/sources/include/tools/inputstate.h new file mode 100644 index 0000000..f05a927 --- /dev/null +++ b/toonz/sources/include/tools/inputstate.h @@ -0,0 +1,227 @@ +#pragma once + +#ifndef INPUTSTATE_INCLUDED +#define INPUTSTATE_INCLUDED + +// TnzTools includes +#include +#include + +// TnzCore includes +#include +#include +#include + +// Qt includes +#include + +// std includes +#include +#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 + + +//==================================================== + +// Forward declarations + +typedef std::vector THoverList; + +//=================================================================== + + +//***************************************************************************************** +// TKey definition +//***************************************************************************************** + +class DVAPI TKey { +public: + Qt::Key key; + bool generic; + bool numPad; + + static const TKey shift; + static const TKey control; + static const TKey alt; + static const TKey meta; + + inline explicit TKey(Qt::Key key = Qt::Key(), bool generic = true, bool numPad = false): + key(key), + generic(generic), + numPad(numPad) + { } + + inline bool operator== (const TKey &other) const { + if (generic || other.generic) + return is(other.key); + return key == other.key && numPad == other.numPad; + } + + inline bool is(Qt::Key key) const + { return mapKey(this->key) == mapKey(key); } + + inline bool isModifier() const + { return isModifier(key); } + inline bool isNumber() const + { return isNumber(key); } + + static Qt::Key mapKey(Qt::Key key); + static bool isNumber(Qt::Key key); + static bool isModifier(Qt::Key key); +}; + + +//***************************************************************************************** +// export template implementations for win32 +//***************************************************************************************** + +#ifdef _WIN32 +template class DVAPI TKeyStateT; +template class DVAPI TSmartPointerT< TKeyStateT >; +template class DVAPI TKeyHistoryT; +template class DVAPI TKeyHistoryT::Holder; + +template class DVAPI TKeyStateT; +template class DVAPI TSmartPointerT< TKeyStateT >; +template class DVAPI TKeyHistoryT; +template class DVAPI TKeyHistoryT::Holder; +#endif + + +//***************************************************************************************** +// TInputState definition +//***************************************************************************************** + +class DVAPI TInputState { +public: + typedef qint64 DeviceId; + typedef long long TouchId; + + typedef TKey Key; + typedef TKeyHistoryT KeyHistory; + typedef KeyHistory::State KeyState; + + typedef Qt::MouseButton Button; + typedef TKeyHistoryT