// TnzCore includes #include "tstream.h" #include "tconvert.h" #include "tsystem.h" #include "tcubicbezier.h" #include "tundo.h" // TnzBase includes #include "tdoublekeyframe.h" #include "tdoubleparamfile.h" #include "texpression.h" #include "tgrammar.h" #include "tparser.h" #include "tunit.h" // STD includes #include #include "tdoubleparam.h" using namespace std; //=============================== class TActualDoubleKeyframe final : public TDoubleKeyframe { public: mutable TExpression m_expression; mutable TDoubleParamFileData m_fileData; TActualDoubleKeyframe(double frame = 0, double value = 0) : TDoubleKeyframe(frame, value), m_unit(0) {} explicit TActualDoubleKeyframe(const TDoubleKeyframe &src) : m_unit(0) { TDoubleKeyframe::operator=(src); if (m_type == Expression || m_type == SimilarShape) m_expression.setText(m_expressionText); else if (m_type == File) m_fileData.setParams(m_fileParams); } TActualDoubleKeyframe &operator=(const TDoubleKeyframe &src) { TDoubleKeyframe::operator=(src); m_unit = 0; if (m_type == Expression || m_type == SimilarShape) { m_expression.setText(m_expressionText); } else if (m_type == File) { m_fileData.setParams(m_fileParams); } return *this; } const TUnit *updateUnit(const TMeasure *measure) { if (!measure) { m_unit = 0; m_unitName = ""; } else { if (m_unitName != "") m_unit = measure->getUnit(::to_wstring(m_unitName)); else m_unit = 0; if (!m_unit) { m_unit = measure->getCurrentUnit(); if (m_unit) { QString app = QString::fromStdWString(m_unit->getDefaultExtension()); m_unitName = app.toStdString(); } } } assert(measure || m_unit == 0 && m_unitName == ""); assert((m_unit == 0) == (m_unitName == "")); QString app = QString::fromStdString(m_unitName); assert(m_unit == 0 || m_unit->isExtension(app.toStdWString())); return m_unit; } double convertFrom(TMeasure *measure, double value) const { if (!m_unit) const_cast(this)->updateUnit(measure); if (m_unit) value = m_unit->convertFrom(value); return value; } private: mutable const TUnit *m_unit; }; typedef vector DoubleKeyframeVector; //=================================================================== inline double getConstantValue(const TActualDoubleKeyframe &k0, const TActualDoubleKeyframe &k1, double f) { return (f == k1.m_frame) ? k1.m_value : k0.m_value; } //--------------------------------------------------------- inline double getLinearValue(const TActualDoubleKeyframe &k0, const TActualDoubleKeyframe &k1, double f) { return k0.m_value + (f - k0.m_frame) * (k1.m_value - k0.m_value) / (k1.m_frame - k0.m_frame); } //--------------------------------------------------------- static void truncateSpeeds(double aFrame, double bFrame, TPointD &aSpeedTrunc, TPointD &bSpeedTrunc) { double deltaX = bFrame - aFrame; if (aSpeedTrunc.x < 0) aSpeedTrunc.x = 0; if (bSpeedTrunc.x > 0) bSpeedTrunc.x = 0; if (aFrame + aSpeedTrunc.x > bFrame) { if (aSpeedTrunc.x != 0) { aSpeedTrunc = aSpeedTrunc * (deltaX / aSpeedTrunc.x); } } if (bFrame + bSpeedTrunc.x < aFrame) { if (bSpeedTrunc.x != 0) { bSpeedTrunc = -bSpeedTrunc * (deltaX / bSpeedTrunc.x); } } } //--------------------------------------------------------- inline double getSpeedInOutValue(const TActualDoubleKeyframe &k0, const TActualDoubleKeyframe &k1, const TPointD &speed0, const TPointD &speed1, double frame) { double aFrame = k0.m_frame; double bFrame = k1.m_frame; double aValue = k0.m_value; double bValue = k1.m_value; if (frame <= aFrame) return aValue; else if (frame >= bFrame) return bValue; TPointD aSpeedTrunc = speed0; TPointD bSpeedTrunc = speed1; truncateSpeeds(aFrame, bFrame, aSpeedTrunc, bSpeedTrunc); return getCubicBezierY(frame, TPointD(aFrame, aValue), aSpeedTrunc, bSpeedTrunc, TPointD(bFrame, bValue)); } //--------------------------------------------------------- DV_EXPORT_API void splitSpeedInOutSegment(TDoubleKeyframe &k, TDoubleKeyframe &k0, TDoubleKeyframe &k1) { if (k.m_frame <= k0.m_frame) { k = k0; return; } else if (k.m_frame >= k1.m_frame) { k = k1; return; } TPointD aSpeed = k0.m_speedOut; TPointD bSpeed = k1.m_speedIn; truncateSpeeds(k0.m_frame, k1.m_frame, aSpeed, bSpeed); TPointD p0(k0.m_frame, k0.m_value); TPointD p3(k1.m_frame, k1.m_value); TPointD p1 = p0 + aSpeed; TPointD p2 = p3 + bSpeed; double t = invCubicBezierX(k.m_frame, p0, aSpeed, bSpeed, p3); t = tcrop(t, 0.0, 1.0); TPointD p01 = (1 - t) * p0 + t * p1; TPointD p12 = (1 - t) * p1 + t * p2; TPointD p23 = (1 - t) * p2 + t * p3; TPointD p012 = (1 - t) * p01 + t * p12; TPointD p123 = (1 - t) * p12 + t * p23; TPointD p = (1 - t) * p012 + t * p123; assert(fabs(p.x - k.m_frame) < 0.1e-3); k.m_value = p.y; k0.m_speedOut = p01 - p0; k.m_speedIn = p012 - p; k.m_speedOut = p123 - p; k1.m_speedIn = p23 - p3; } //--------------------------------------------------------- inline double getEaseInOutValue(const TActualDoubleKeyframe &k0, const TActualDoubleKeyframe &k1, double frame, bool percentage) { double x3 = k1.m_frame - k0.m_frame; if (x3 <= 0.0) return k0.m_value; double x = frame - k0.m_frame; if (x <= 0) return k0.m_value; else if (x >= x3) return k1.m_value; double e0 = std::max(k0.m_speedOut.x, 0.0); double e1 = std::max(-k1.m_speedIn.x, 0.0); if (percentage) { e0 *= x3 * 0.01; e1 *= x3 * 0.01; } if (e0 + e1 >= x3) { double x = tcrop((e0 + x3 - e1) / 2, 0.0, x3); e0 = x; e1 = x3 - x; } double x1 = e0, x2 = x3 - e1; if (0 < x1 - x2 && x1 - x2 < 0.1e-5) x1 = x2 = (x1 + x2) * 0.5; // against rounding problems assert(0 <= x1 && x1 <= x2 && x2 <= x3); double v = 2 / (x3 + x2 - x1); double value = 0; if (x < x1) { double a = v / e0; value = 0.5 * a * x * x; } else if (x > x2) { double a = v / e1; value = 1 - 0.5 * a * (x3 - x) * (x3 - x); } else { double c = -0.5 * v * e0; value = x * v + c; } return (1 - value) * k0.m_value + value * k1.m_value; } //--------------------------------------------------------- inline double getExponentialValue(const TActualDoubleKeyframe &k0, const TActualDoubleKeyframe &k1, double frame) { double aFrame = k0.m_frame; double bFrame = k1.m_frame; double deltaX = bFrame - aFrame; double aValue = k0.m_value; double bValue = k1.m_value; // if min(aValue,bValue)<=0 => error => linear if (aValue <= 0 || bValue <= 0) return getLinearValue(k0, k1, frame); double t = (frame - aFrame) / deltaX; // if aValue k0.m_frame) t = rframe / (k1.m_frame - k0.m_frame); TSyntax::Calculator *calculator = k0.m_expression.getCalculator(); if (calculator) { calculator->setUnit( (const_cast(k0)).updateUnit(measure)); return calculator->compute(t, frame + 1, rframe + 1); } else if (measure) return measure->getDefaultValue(); else return 0; } //--------------------------------------------------------- inline double getSimilarShapeValue(const TActualDoubleKeyframe &k0, const TActualDoubleKeyframe &k1, double frame, const TMeasure *measure) { double offset = k0.m_similarShapeOffset; double rv0 = getExpressionValue(k0, k1, k0.m_frame + offset, measure); double rv1 = getExpressionValue(k0, k1, k1.m_frame + offset, measure); double rv = getExpressionValue(k0, k1, frame + offset, measure); double v0 = k0.m_value; double v1 = k1.m_value; if (rv1 != rv0) return v0 + (v1 - v0) * (rv - rv0) / (rv1 - rv0); else if (measure) return measure->getDefaultValue(); else return 0; } //=================================================================== class TDoubleParam::Imp { public: const TSyntax::Grammar *m_grammar; string m_measureName; TMeasure *m_measure; double m_defaultValue, m_minValue, m_maxValue; DoubleKeyframeVector m_keyframes; bool m_cycleEnabled; std::set m_observers; Imp(double v = 0.0) : m_grammar(0) , m_measureName() , m_measure(0) , m_defaultValue(v) , m_minValue(-(std::numeric_limits::max)()) , m_maxValue((std::numeric_limits::max)()) , m_cycleEnabled(false) {} ~Imp() {} void copy(std::unique_ptr const &src) { m_grammar = src->m_grammar; m_measureName = src->m_measureName; m_measure = src->m_measure; m_defaultValue = src->m_defaultValue; m_minValue = src->m_minValue; m_maxValue = src->m_maxValue; m_keyframes = src->m_keyframes; m_cycleEnabled = src->m_cycleEnabled; } void notify(const TParamChange &change) { std::set::iterator it = m_observers.begin(); for (; it != m_observers.end(); ++it) (*it)->onChange(change); } double getValue(int segmentIndex, double frame); double getSpeed(int segmentIndex, double frame); TPointD getSpeedIn(int kIndex); TPointD getSpeedOut(int kIndex); }; //--------------------------------------------------------- double TDoubleParam::Imp::getValue(int segmentIndex, double frame) { assert(0 <= segmentIndex && segmentIndex + 1 < (int)m_keyframes.size()); const TActualDoubleKeyframe &k0 = m_keyframes[segmentIndex]; const TActualDoubleKeyframe &k1 = m_keyframes[segmentIndex + 1]; double value = m_defaultValue; bool convertUnit = false; switch (k0.m_type) { case TDoubleKeyframe::Constant: value = getConstantValue(k0, k1, frame); break; case TDoubleKeyframe::Linear: value = getLinearValue(k0, k1, frame); break; case TDoubleKeyframe::SpeedInOut: value = getSpeedInOutValue(k0, k1, getSpeedOut(segmentIndex), getSpeedIn(segmentIndex + 1), frame); break; case TDoubleKeyframe::EaseInOut: value = getEaseInOutValue(k0, k1, frame, false); break; case TDoubleKeyframe::EaseInOutPercentage: value = getEaseInOutValue(k0, k1, frame, true); break; case TDoubleKeyframe::Exponential: value = getExponentialValue(k0, k1, frame); break; case TDoubleKeyframe::Expression: value = getExpressionValue(k0, k1, frame, m_measure); convertUnit = true; break; case TDoubleKeyframe::File: value = k0.m_fileData.getValue(frame, m_defaultValue); convertUnit = true; break; case TDoubleKeyframe::SimilarShape: value = getSimilarShapeValue(k0, k1, frame, m_measure); break; } if (convertUnit) value = k0.convertFrom(m_measure, value); return value; } //--------------------------------------------------------- double TDoubleParam::Imp::getSpeed(int segmentIndex, double frame) { const double h = 0.00001; return (getValue(segmentIndex, frame + h) - getValue(segmentIndex, frame - h)) / (2 * h); } //--------------------------------------------------------- TPointD TDoubleParam::Imp::getSpeedIn(int kIndex) { assert(1 <= kIndex && kIndex < (int)m_keyframes.size()); const TActualDoubleKeyframe &kf0 = m_keyframes[kIndex - 1]; const TActualDoubleKeyframe &kf1 = m_keyframes[kIndex]; assert(kf0.m_type == TDoubleKeyframe::SpeedInOut); if (!kf1.m_linkedHandles) return kf1.m_speedIn; TPointD speedIn = kf1.m_speedIn; if (kIndex + 1 >= (int)m_keyframes.size()) { // speedIn.y = 0; } else { if (kf1.m_type != TDoubleKeyframe::SpeedInOut && (kf1.m_type != TDoubleKeyframe::Expression || !kf1.m_expression.isCycling())) { double speed = getSpeed(kIndex, kf1.m_frame); speedIn.y = speedIn.x * speed; } } return speedIn; } //--------------------------------------------------------- TPointD TDoubleParam::Imp::getSpeedOut(int kIndex) { assert(0 <= kIndex && kIndex < (int)m_keyframes.size()); const TDoubleKeyframe &kf1 = m_keyframes[kIndex]; assert(kf1.m_type == TDoubleKeyframe::SpeedInOut); if (!kf1.m_linkedHandles) return kf1.m_speedOut; TPointD speedOut = kf1.m_speedOut; if (kIndex == 0) { // speedOut.y = 0; } else { const TDoubleKeyframe &kf0 = m_keyframes[kIndex - 1]; if (kf0.m_type != TDoubleKeyframe::SpeedInOut) { double speed = getSpeed(kIndex - 1, kf1.m_frame); speedOut.y = speedOut.x * speed; } } return speedOut; } //--------------------------------------------------------- TPointD TDoubleParam::getSpeedIn(int kIndex) const { return m_imp->getSpeedIn(kIndex); } TPointD TDoubleParam::getSpeedOut(int kIndex) const { return m_imp->getSpeedOut(kIndex); } //========================================================= PERSIST_IDENTIFIER(TDoubleParam, "doubleParam") //--------------------------------------------------------- TDoubleParam::TDoubleParam(double v) : m_imp(new TDoubleParam::Imp(v)) {} //--------------------------------------------------------- TDoubleParam::TDoubleParam(const TDoubleParam &src) : TParam(src.getName()), m_imp(new TDoubleParam::Imp()) { m_imp->copy(src.m_imp); } //--------------------------------------------------------- TDoubleParam::~TDoubleParam() {} //--------------------------------------------------------- TDoubleParam &TDoubleParam::operator=(const TDoubleParam &dp) { setName(dp.getName()); m_imp->copy(dp.m_imp); return *this; } //--------------------------------------------------------- void TDoubleParam::copy(TParam *src) { TDoubleParam *p = dynamic_cast(src); if (!p) throw TException("invalid source for copy"); setName(src->getName()); m_imp->copy(p->m_imp); m_imp->notify(TParamChange(this, 0, 0, true, false, false)); } //--------------------------------------------------------- void TDoubleParam::setValueRange(double min, double max, double step) { if (min > max) min = max; m_imp->m_minValue = min; m_imp->m_maxValue = max; // m_imp->m_valueStep = step; } //--------------------------------------------------------- bool TDoubleParam::getValueRange(double &min, double &max, double &step) const { min = m_imp->m_minValue; max = m_imp->m_maxValue; step = 1; // m_imp->m_valueStep; return min < max; } //--------------------------------------------------------- double TDoubleParam::getDefaultValue() const { assert(m_imp); return m_imp->m_defaultValue; } //--------------------------------------------------------- void TDoubleParam::enableCycle(bool enabled) { m_imp->m_cycleEnabled = enabled; m_imp->notify(TParamChange(this, 0, 0, true, false, false)); } //--------------------------------------------------------- bool TDoubleParam::isCycleEnabled() const { return m_imp->m_cycleEnabled; } //========================================================= //========================================================= double TDoubleParam::getValue(double frame, bool leftmost) const { double value = 0; assert(m_imp); const DoubleKeyframeVector &keyframes = m_imp->m_keyframes; if (keyframes.empty()) { // no keyframes: return the default value value = m_imp->m_defaultValue; } else if (keyframes.size() == 1) { // a single keyframe. Type must be keyframe based (no expression/file) value = keyframes[0].m_value; } else { // keyframes range is [f0,f1] double f0 = keyframes.begin()->m_frame; double f1 = keyframes.back().m_frame; if (frame < f0) frame = f0; else if (frame > f1 && !m_imp->m_cycleEnabled) frame = f1; double valueOffset = 0; if (m_imp->m_cycleEnabled) { double dist = (f1 - f0); double dvalue = keyframes.back().m_value - keyframes.begin()->m_value; while (frame >= f1) { if (frame != f1 || !leftmost) { frame -= dist; valueOffset += dvalue; } else break; } } // frame is in [f0,f1] assert(f0 <= frame && frame <= f1); DoubleKeyframeVector::const_iterator b; b = std::lower_bound(keyframes.begin(), keyframes.end(), TDoubleKeyframe(frame)); assert(b != keyframes.end()); DoubleKeyframeVector::const_iterator a; if (b->m_frame == frame && (b + 1) != keyframes.end()) { a = b; b++; } else { assert(b != keyframes.begin()); a = b - 1; } if (leftmost && frame - a->m_frame < 0.00001 && a != keyframes.begin()) { a--; b--; } // segment (a,b) contains frame assert(a != keyframes.end()); assert(b != keyframes.end()); assert(a->m_frame <= frame); assert(b->m_frame >= frame); int kIndex = std::distance(keyframes.begin(), a); vector tmpKeyframe(3); // if segment is keyframe based .... if (TDoubleKeyframe::isKeyframeBased(a->m_type)) { // .. and next segment is not then update the b value if ((b + 1) != keyframes.end() && !TDoubleKeyframe::isKeyframeBased(b->m_type)) { tmpKeyframe[0] = *b; if (b->m_type != TDoubleKeyframe::Expression || !b->m_expression.isCycling()) tmpKeyframe[0].m_value = getValue(b->m_frame); b = tmpKeyframe.begin(); } // .. and/or if prev segment is not then update the a value if (a != keyframes.begin() && !TDoubleKeyframe::isKeyframeBased(a[-1].m_type)) { tmpKeyframe[1] = *a; tmpKeyframe[1].m_value = getValue(a->m_frame, true); a = tmpKeyframe.begin() + 1; } } if (a->m_step > 1) { tmpKeyframe[2] = *b; b = tmpKeyframe.begin() + 2; int relPos = tfloor(b->m_frame - a->m_frame), step = std::min(a->m_step, relPos); tmpKeyframe[2].m_frame = a->m_frame + tfloor(relPos, step); if (frame > b->m_frame) frame = b->m_frame; frame = a->m_frame + tfloor(tfloor(frame - a->m_frame), step); } assert(0 <= kIndex && kIndex + 1 < (int)m_imp->m_keyframes.size()); value = m_imp->m_defaultValue; bool convertUnit = false; switch (a->m_type) { case TDoubleKeyframe::Constant: value = getConstantValue(*a, *b, frame); break; case TDoubleKeyframe::Linear: value = getLinearValue(*a, *b, frame); break; case TDoubleKeyframe::SpeedInOut: value = getSpeedInOutValue(*a, *b, getSpeedOut(kIndex), getSpeedIn(kIndex + 1), frame); break; case TDoubleKeyframe::EaseInOut: value = getEaseInOutValue(*a, *b, frame, false); break; case TDoubleKeyframe::EaseInOutPercentage: value = getEaseInOutValue(*a, *b, frame, true); break; case TDoubleKeyframe::Exponential: value = getExponentialValue(*a, *b, frame); break; case TDoubleKeyframe::Expression: value = getExpressionValue(*a, *b, frame, m_imp->m_measure); convertUnit = true; break; case TDoubleKeyframe::File: value = a->m_fileData.getValue(frame, m_imp->m_defaultValue); convertUnit = true; break; case TDoubleKeyframe::SimilarShape: value = getSimilarShapeValue(*a, *b, frame, m_imp->m_measure); // convertUnit = true; break; default: value = 0.0; } value += valueOffset; if (convertUnit) value = a->convertFrom(m_imp->m_measure, value); } // if (cropped) // value = tcrop(value, m_imp->m_minValue, m_imp->m_maxValue); return value; } //--------------------------------------------------------- bool TDoubleParam::setValue(double frame, double value) { assert(m_imp); DoubleKeyframeVector &keyframes = m_imp->m_keyframes; DoubleKeyframeVector::iterator it; TActualDoubleKeyframe k(frame); it = std::lower_bound(keyframes.begin(), keyframes.end(), k); int index = 0; bool created = false; /*-- キーフレームが見つかった場合 --*/ if (it != keyframes.end() && it->m_frame == frame) { // changing a keyframe value index = std::distance(keyframes.begin(), it); TActualDoubleKeyframe oldKeyframe = *it; if (oldKeyframe.m_type == TDoubleKeyframe::Expression || oldKeyframe.m_type == TDoubleKeyframe::File) return false; it->m_value = value; m_imp->notify(TParamChange(this, 0, 0, true, false, false)); } /*-- セグメントの部分なので、新たにキーフレームを作る --*/ else { assert(it == keyframes.end() || it->m_frame > frame); // can't change value in a file/expression segment if (it != keyframes.end() && it > keyframes.begin() && ((it - 1)->m_type == TDoubleKeyframe::Expression || (it - 1)->m_type == TDoubleKeyframe::File)) return false; // inserting a new keyframe k.m_value = value; k.m_isKeyframe = true; k.m_expression.setGrammar(m_imp->m_grammar); k.m_expression.setOwnerParameter(this); it = keyframes.insert(it, k); if (it == keyframes.begin()) it->m_prevType = TDoubleKeyframe::None; else { it->m_prevType = it[-1].m_type; /*-- FxGuiでSegment内にKeyを打った場合は、Step値も引き継ぐ --*/ it->m_step = it[-1].m_step; } if (it + 1 != keyframes.end()) it[1].m_prevType = it->m_type; index = std::distance(keyframes.begin(), it); m_imp->notify(TParamChange(this, 0, 0, true, false, false)); created = true; } assert(0 == index || keyframes[index - 1].m_frame < keyframes[index].m_frame); assert(getKeyframeCount() - 1 == index || keyframes[index + 1].m_frame > keyframes[index].m_frame); return created; } //--------------------------------------------------------- void TDoubleParam::setKeyframe(int index, const TDoubleKeyframe &k) { DoubleKeyframeVector &keyframes = m_imp->m_keyframes; assert(0 <= index && index < (int)keyframes.size()); TActualDoubleKeyframe &dst = keyframes[index]; TActualDoubleKeyframe oldKeyframe = dst; (TDoubleKeyframe &)dst = k; dst.updateUnit(m_imp->m_measure); if (dst.m_type == TDoubleKeyframe::Expression || dst.m_type == TDoubleKeyframe::SimilarShape) dst.m_expression.setText(dst.m_expressionText); if (dst.m_type == TDoubleKeyframe::File) dst.m_fileData.setParams(dst.m_fileParams); m_imp->notify(TParamChange(this, 0, 0, true, false, false)); assert(0 == index || keyframes[index - 1].m_frame < keyframes[index].m_frame); assert(getKeyframeCount() - 1 == index || keyframes[index + 1].m_frame > keyframes[index].m_frame); if (index == 0) dst.m_prevType = TDoubleKeyframe::None; else dst.m_prevType = keyframes[index - 1].m_type; } //--------------------------------------------------------- void TDoubleParam::setKeyframes(const std::map &ks) { DoubleKeyframeVector &keyframes = m_imp->m_keyframes; std::map::const_iterator it; for (it = ks.begin(); it != ks.end(); ++it) { int index = it->first; assert(0 <= index && index < (int)keyframes.size()); TActualDoubleKeyframe oldKeyframe = keyframes[index]; TActualDoubleKeyframe &dst = keyframes[index]; (TDoubleKeyframe &)dst = it->second; dst.updateUnit(m_imp->m_measure); if (dst.m_type == TDoubleKeyframe::Expression || dst.m_type == TDoubleKeyframe::SimilarShape) dst.m_expression.setText(dst.m_expressionText); if (dst.m_type == TDoubleKeyframe::File) dst.m_fileData.setParams(dst.m_fileParams); } if (!keyframes.empty()) { keyframes[0].m_prevType = TDoubleKeyframe::None; for (int i = 1; i < (int)keyframes.size(); i++) keyframes[i].m_prevType = keyframes[i - 1].m_type; } m_imp->notify(TParamChange(this, 0, 0, true, false, false)); #ifndef NDEBUG for (int i = 0; i + 1 < (int)keyframes.size(); i++) { assert(keyframes[i].m_frame <= keyframes[i + 1].m_frame); } #endif } //--------------------------------------------------------- void TDoubleParam::setKeyframe(const TDoubleKeyframe &k) { DoubleKeyframeVector &keyframes = m_imp->m_keyframes; DoubleKeyframeVector::iterator it; it = std::lower_bound(keyframes.begin(), keyframes.end(), k); if (it != keyframes.end() && it->m_frame == k.m_frame) { // int index = std::distance(keyframes.begin(), it); TActualDoubleKeyframe &dst = *it; (TDoubleKeyframe &)dst = k; dst.updateUnit(m_imp->m_measure); } else { it = keyframes.insert(it, TActualDoubleKeyframe(k)); // int index = std::distance(keyframes.begin(), it); // TDoubleKeyframe oldKeyframe = *it; it->m_expression.setGrammar(m_imp->m_grammar); it->m_expression.setOwnerParameter(this); it->updateUnit(m_imp->m_measure); } it->m_isKeyframe = true; if (it->m_type == TDoubleKeyframe::Expression) it->m_expression.setText(it->m_expressionText); if (it->m_type == TDoubleKeyframe::File) it->m_fileData.setParams(it->m_fileParams); if (it == keyframes.begin()) it->m_prevType = TDoubleKeyframe::None; else it->m_prevType = it[-1].m_type; m_imp->notify(TParamChange(this, 0, 0, true, false, false)); assert(it == keyframes.begin() || (it - 1)->m_frame < it->m_frame); assert(it + 1 == keyframes.end() || (it + 1)->m_frame > it->m_frame); } //--------------------------------------------------------- void TDoubleParam::setDefaultValue(double value) { assert(m_imp); if (m_imp->m_defaultValue != value) { m_imp->m_defaultValue = value; // gmt, 19-6-2010; needed to get a notification in the FxParamsGraphicEditor // (Camera Stand) // when a param (without keyframes) is changed m_imp->notify(TParamChange(this, 0, 0, true, false, false)); } } //--------------------------------------------------------- bool TDoubleParam::isDefault() const { return m_imp->m_keyframes.empty() && // m_imp->m_type == Keyframes && m_imp->m_defaultValue == 0; } //--------------------------------------------------------- int TDoubleParam::getKeyframeCount() const { return m_imp->m_keyframes.size(); } //--------------------------------------------------------- void TDoubleParam::getKeyframes(std::set &frames) const { for (DoubleKeyframeVector::iterator it = m_imp->m_keyframes.begin(); it != m_imp->m_keyframes.end(); ++it) frames.insert(it->m_frame); } //--------------------------------------------------------- bool TDoubleParam::hasKeyframes() const { return !m_imp->m_keyframes.empty(); } //--------------------------------------------------------- const TDoubleKeyframe &TDoubleParam::getKeyframe(int index) const { assert(0 <= index && index < (int)m_imp->m_keyframes.size()); return m_imp->m_keyframes[index]; } //--------------------------------------------------------- const TDoubleKeyframe &TDoubleParam::getKeyframeAt(double frame) const { static TDoubleKeyframe k; k = TDoubleKeyframe(); int i = 0; for (i = 0; i < (int)m_imp->m_keyframes.size(); i++) if (m_imp->m_keyframes[i].m_frame >= frame) break; if (i < (int)m_imp->m_keyframes.size() && m_imp->m_keyframes[i].m_frame == frame) { k = m_imp->m_keyframes[i]; return k; } k.m_frame = frame; k.m_value = getValue(frame); k.m_isKeyframe = false; return k; } //--------------------------------------------------------- bool TDoubleParam::isKeyframe(double frame) const { return std::binary_search(m_imp->m_keyframes.begin(), m_imp->m_keyframes.end(), TDoubleKeyframe(frame)); } //--------------------------------------------------------- void TDoubleParam::deleteKeyframe(double frame) { DoubleKeyframeVector &keyframes = m_imp->m_keyframes; DoubleKeyframeVector::iterator it; it = std::lower_bound(keyframes.begin(), keyframes.end(), TDoubleKeyframe(frame)); if (it == keyframes.end() || it->m_frame != frame) return; TDoubleKeyframe::Type type = it->m_prevType; it = m_imp->m_keyframes.erase(it); if (it != keyframes.end()) it->m_prevType = type; m_imp->notify(TParamChange(this, 0, 0, true, false, false)); } //--------------------------------------------------------- void TDoubleParam::clearKeyframes() { m_imp->m_keyframes.clear(); m_imp->notify(TParamChange(this, 0, 0, true, false, false)); } //--------------------------------------------------------- void TDoubleParam::assignKeyframe(double frame, const TParamP &src, double srcFrame, bool changedOnly) { TDoubleParamP dp = src; if (!dp) return; double value = dp->getValue(srcFrame); if (!changedOnly || getValue(frame) != value) setValue(frame, value); } //--------------------------------------------------------- int TDoubleParam::getClosestKeyframe(double frame) const { DoubleKeyframeVector &keyframes = m_imp->m_keyframes; typedef DoubleKeyframeVector::iterator Iterator; Iterator it = std::lower_bound(keyframes.begin(), keyframes.end(), TDoubleKeyframe(frame)); if (it == keyframes.end()) { // frame > k.m_frame per qualsiasi k. // ritorna l'indice dell'ultimo keyframe (o -1 se l'array e' vuoto) return keyframes.size() - 1; } else { int index = std::distance(keyframes.begin(), it); if (it->m_frame == frame || index == 0) return index; else { double nextFrame = it->m_frame; double prevFrame = keyframes[index - 1].m_frame; assert(prevFrame < frame && frame < nextFrame); return (nextFrame - frame < frame - prevFrame) ? index : index - 1; } } } //--------------------------------------------------------- int TDoubleParam::getNextKeyframe(double frame) const { TDoubleKeyframe k(frame); typedef DoubleKeyframeVector::const_iterator Iterator; Iterator it = std::upper_bound(m_imp->m_keyframes.begin(), m_imp->m_keyframes.end(), k); if (it == m_imp->m_keyframes.end()) return -1; int index = std::distance(m_imp->m_keyframes.begin(), it); if (it->m_frame == frame) { ++index; return index < getKeyframeCount() ? index : -1; } return index; } //--------------------------------------------------------- int TDoubleParam::getPrevKeyframe(double frame) const { TDoubleKeyframe k(frame); typedef DoubleKeyframeVector::const_iterator Iterator; Iterator it = std::lower_bound(m_imp->m_keyframes.begin(), m_imp->m_keyframes.end(), k); if (it == m_imp->m_keyframes.end()) return m_imp->m_keyframes.size() - 1; int index = std::distance(m_imp->m_keyframes.begin(), it); return index - 1; } //--------------------------------------------------------- double TDoubleParam::keyframeIndexToFrame(int index) const { assert(0 <= index && index < getKeyframeCount()); return getKeyframe(index).m_frame; } //--------------------------------------------------------- void TDoubleParam::addObserver(TParamObserver *observer) { m_imp->m_observers.insert(observer); } //--------------------------------------------------------- void TDoubleParam::removeObserver(TParamObserver *observer) { m_imp->m_observers.erase(observer); } //--------------------------------------------------------- const std::set &TDoubleParam::observers() const { return m_imp->m_observers; } //--------------------------------------------------------- void TDoubleParam::loadData(TIStream &is) { string tagName; /* if(is.matchTag(tagName)) { // nuovo formato (29 agosto 2005) if(tagName!="type") throw TException("expected "); int type = 0; is >> type; // m_imp->m_type = TDoubleParam::Type(type); if(!is.matchEndTag()) throw TException(tagName + " : missing endtag"); //if(!is.matchTag(tagName) || tagName != "default") throw TException("expected "); //is >> m_imp->m_defaultValue; //if(!is.matchEndTag()) throw TException(tagName + " : missing endtag"); //if(!is.matchTag(tagName) || tagName != "default") throw TException("expected "); } else { // vecchio formato is >> m_imp->m_defaultValue; } */ m_imp->m_keyframes.clear(); int oldType = -1; while (is.matchTag(tagName)) { if (tagName == "type") { // (old) format 5.2. Since 6.0 param type is no used anymore is >> oldType; } else if (tagName == "default") { is >> m_imp->m_defaultValue; } else if (tagName == "cycle") { string dummy; is >> dummy; m_imp->m_cycleEnabled = true; // setExtrapolationAfter(Loop); } else if (tagName == "k") { // vecchio formato if (oldType != 0) continue; int linkStatus = 0; TActualDoubleKeyframe k; is >> k.m_frame >> k.m_value >> k.m_speedIn.x >> k.m_speedIn.y >> k.m_speedOut.x >> k.m_speedOut.y >> linkStatus; k.m_isKeyframe = true; k.m_linkedHandles = (linkStatus & 1) != 0; if ((linkStatus & 1) != 0) k.m_type = TDoubleKeyframe::SpeedInOut; else if ((linkStatus & 2) != 0 || (linkStatus & 4) != 0) k.m_type = TDoubleKeyframe::EaseInOut; else k.m_type = TDoubleKeyframe::Linear; k.m_expression.setGrammar(m_imp->m_grammar); k.m_expression.setOwnerParameter(this); k.m_prevType = m_imp->m_keyframes.empty() ? TDoubleKeyframe::None : m_imp->m_keyframes.back().m_type; m_imp->m_keyframes.push_back(k); } else if (tagName == "expr") { // vecchio formato if (oldType != 1) continue; string text = is.getTagAttribute("text"); string enabled = is.getTagAttribute("enabled"); TDoubleKeyframe kk1, kk2; kk1.m_frame = -1000; kk2.m_frame = 1000; kk1.m_isKeyframe = true; kk2.m_isKeyframe = true; kk1.m_expressionText = text; kk2.m_expressionText = text; kk1.m_type = TDoubleKeyframe::Expression; kk2.m_type = TDoubleKeyframe::Expression; TActualDoubleKeyframe k1(kk1); TActualDoubleKeyframe k2(kk2); k1.m_expression.setGrammar(m_imp->m_grammar); k1.m_expression.setOwnerParameter(this); k1.m_prevType = m_imp->m_keyframes.empty() ? TDoubleKeyframe::None : m_imp->m_keyframes.back().m_type; k2.m_expression.setGrammar(m_imp->m_grammar); k2.m_expression.setOwnerParameter(this); k2.m_prevType = m_imp->m_keyframes.empty() ? TDoubleKeyframe::None : m_imp->m_keyframes.back().m_type; m_imp->m_keyframes.push_back(k1); m_imp->m_keyframes.push_back(k2); continue; } else if (tagName == "file") { // vecchio formato if (oldType != 2) continue; TDoubleKeyframe::FileParams params; params.m_path = TFilePath(is.getTagAttribute("path")); params.m_fieldIndex = std::stoi(is.getTagAttribute("index")); TActualDoubleKeyframe k1, k2; k1.m_frame = -1000; k2.m_frame = 1000; k1.m_isKeyframe = true; k2.m_isKeyframe = true; k1.m_fileData.setParams(params); k2.m_fileData.setParams(params); k1.m_type = TDoubleKeyframe::File; k2.m_type = TDoubleKeyframe::File; k1.m_expression.setGrammar(m_imp->m_grammar); k1.m_expression.setOwnerParameter(this); k1.m_prevType = m_imp->m_keyframes.empty() ? TDoubleKeyframe::None : m_imp->m_keyframes.back().m_type; k2.m_expression.setGrammar(m_imp->m_grammar); k2.m_expression.setOwnerParameter(this); k2.m_prevType = m_imp->m_keyframes.empty() ? TDoubleKeyframe::None : m_imp->m_keyframes.back().m_type; m_imp->m_keyframes.push_back(k1); m_imp->m_keyframes.push_back(k2); continue; } else if (tagName == "step") { int step = 0; is >> step; // if(step>1) // m_imp->m_frameStep = step; } else if (tagName == "keyframes") { while (!is.eos()) { TDoubleKeyframe kk; kk.loadData(is); TActualDoubleKeyframe k(kk); k.m_expression.setGrammar(m_imp->m_grammar); k.m_expression.setOwnerParameter(this); k.m_prevType = m_imp->m_keyframes.empty() ? TDoubleKeyframe::None : m_imp->m_keyframes.back().m_type; m_imp->m_keyframes.push_back(k); } } else { throw TException(tagName + " : unexpected tag"); } if (!is.matchEndTag()) throw TException(tagName + " : missing endtag"); } if (m_imp->m_keyframes.empty() && !is.eos()) { // vecchio sistema (prima 16/1/2003) while (!is.eos()) { double t, v; is >> t >> v; m_imp->m_keyframes.push_back(TActualDoubleKeyframe(t, v)); } if (!m_imp->m_keyframes.empty()) { m_imp->m_keyframes[0].m_prevType = TDoubleKeyframe::None; for (int i = 1; i < (int)m_imp->m_keyframes.size(); i++) m_imp->m_keyframes[i].m_prevType = m_imp->m_keyframes[i - 1].m_type; } } m_imp->notify(TParamChange(this, 0, 0, true, false, false)); } //--------------------------------------------------------- void TDoubleParam::saveData(TOStream &os) { // os.child("type") << (int)m_imp->m_type; os.child("default") << m_imp->m_defaultValue; if (isCycleEnabled()) os.child("cycle") << std::string("enabled"); // if(getExtrapolationAfter() == Loop) // os.child("cycle") << string("loop"); if (!m_imp->m_keyframes.empty()) { os.openChild("keyframes"); DoubleKeyframeVector::const_iterator it; for (it = m_imp->m_keyframes.begin(); it != m_imp->m_keyframes.end(); ++it) it->saveData(os); os.closeChild(); } } //--------------------------------------------------------- string TDoubleParam::getStreamTag() const { return "doubleParam"; } //------------------------------------------------------------------- string TDoubleParam::getValueAlias(double frame, int precision) { return ::to_string(getValue(frame), precision); } //------------------------------------------------------------------- void TDoubleParam::setGrammar(const TSyntax::Grammar *grammar) { m_imp->m_grammar = grammar; for (int i = 0; i < (int)m_imp->m_keyframes.size(); i++) m_imp->m_keyframes[i].m_expression.setGrammar(grammar); } //------------------------------------------------------------------- const TSyntax::Grammar *TDoubleParam::getGrammar() const { return m_imp->m_grammar; } //------------------------------------------------------------------- void TDoubleParam::accept(TSyntax::CalculatorNodeVisitor &visitor) { for (int i = 0; i < (int)m_imp->m_keyframes.size(); i++) if (m_imp->m_keyframes[i].m_type == TDoubleKeyframe::Expression || m_imp->m_keyframes[i].m_type == TDoubleKeyframe::SimilarShape) m_imp->m_keyframes[i].m_expression.accept(visitor); } //------------------------------------------------------------------- string TDoubleParam::getMeasureName() const { return m_imp->m_measureName; } //------------------------------------------------------------------- void TDoubleParam::setMeasureName(string name) { m_imp->m_measureName = name; m_imp->m_measure = TMeasureManager::instance()->get(name); } //------------------------------------------------------------------- TMeasure *TDoubleParam::getMeasure() const { return m_imp->m_measure; }