From 3d206c1d227f01d57e8f37e6bece286c2b6d6090 Mon Sep 17 00:00:00 2001 From: mfeemster Date: Wed, 25 Mar 2015 20:47:57 -0700 Subject: [PATCH] Fix bug where xform fields that were not specified for motion interpolation were still getting interpolated. Carry logic from this fix to writing Xform Xmls as well. Motion was not supported on some Xform fields as it was originally copied from flam3. Allow it on all but xaos now. Fix clamping range for m_ColorSpeed at the end of ApplyMotion() to match the values we accept elsewhere. --- Source/Ember/Affine2D.cpp | 15 ++++ Source/Ember/Affine2D.h | 1 + Source/Ember/EmberDefines.h | 1 + Source/Ember/EmberToXml.h | 21 +++--- Source/Ember/Xform.h | 113 ++++++++++++++++++++--------- Source/Ember/XmlToEmber.h | 2 +- Source/EmberTester/EmberTester.cpp | 4 +- 7 files changed, 107 insertions(+), 50 deletions(-) diff --git a/Source/Ember/Affine2D.cpp b/Source/Ember/Affine2D.cpp index 083f2a0..b02839a 100644 --- a/Source/Ember/Affine2D.cpp +++ b/Source/Ember/Affine2D.cpp @@ -157,6 +157,21 @@ bool Affine2D::IsZero() const (IsClose(F(), 0)); } +/// +/// Determine whether this affine transform was deliberately set to all empty values. +/// +/// True if all 6 elements equal zero, else false. +template +bool Affine2D::IsEmpty() const +{ + return (IsClose(A(), EMPTYFIELD)) && + (IsClose(B(), EMPTYFIELD)) && + (IsClose(C(), EMPTYFIELD)) && + (IsClose(D(), EMPTYFIELD)) && + (IsClose(E(), EMPTYFIELD)) && + (IsClose(F(), EMPTYFIELD)); +} + /// /// Rotate this affine transform around its origin by the specified angle in degrees. /// diff --git a/Source/Ember/Affine2D.h b/Source/Ember/Affine2D.h index 162d9b8..a96f6c6 100644 --- a/Source/Ember/Affine2D.h +++ b/Source/Ember/Affine2D.h @@ -74,6 +74,7 @@ public: void MakeID(); bool IsID() const; bool IsZero() const; + bool IsEmpty() const; void Rotate(T angle); void Translate(const v2T& v); void RotateScaleXTo(const v2T& v); diff --git a/Source/Ember/EmberDefines.h b/Source/Ember/EmberDefines.h index d18279e..cb1c2ed 100644 --- a/Source/Ember/EmberDefines.h +++ b/Source/Ember/EmberDefines.h @@ -74,6 +74,7 @@ namespace EmberNs #define TMAX std::numeric_limits::max() #define FLOAT_MAX_TAN 8388607.0f #define FLOAT_MIN_TAN -FLOAT_MAX_TAN +#define EMPTYFIELD -9999 typedef std::chrono::high_resolution_clock Clock; #ifndef byte diff --git a/Source/Ember/EmberToXml.h b/Source/Ember/EmberToXml.h index e765e51..5f3e402 100644 --- a/Source/Ember/EmberToXml.h +++ b/Source/Ember/EmberToXml.h @@ -493,14 +493,14 @@ private: os << " - /// Default constructor which calls Init() to set default values. - /// Pre and post affine are defaulted to the identity matrix. + /// Default constructor which calls Init() to set default or out of bounds values. + /// When useDefaults is true, Pre and post affine are defaulted to the identity matrix. /// - Xform() + /// Use reasonable default if true, else use out of bounds values. + Xform(bool useDefaults = true) { - Init(); + Init(useDefaults); } /// @@ -196,36 +197,73 @@ public: /// /// Init default values. + /// Non default values are used to signify an uninitialized state. This is useful for + /// doing motion interpolation where we don't want to apply motion to all fields. By setting + /// unreasonable values before parsing, then only assigning the ones the motion tags specified, + /// it is clear which fields are intended to have motion applied to them. /// - void Init() + /// Use reasonable default if true, else use out of bounds values. + void Init(bool useDefaults = true) { static size_t count = 0; - m_Weight = 0; - m_ColorSpeed = T(0.5); - m_Animate = 1; - m_ColorX = T(count & 1); - m_ColorY = 0; - m_DirectColor = 1; - m_Opacity = 1; + if (useDefaults) + { + m_Weight = 0; + m_ColorSpeed = T(0.5); + m_Animate = 1; + m_ColorX = T(count & 1); + m_ColorY = 0; + m_DirectColor = 1; + m_Opacity = 1; - m_Affine.A(1); - m_Affine.B(0); - m_Affine.C(0); - m_Affine.D(0); - m_Affine.E(1); - m_Affine.F(0); + m_Affine.A(1); + m_Affine.B(0); + m_Affine.C(0); + m_Affine.D(0); + m_Affine.E(1); + m_Affine.F(0); - m_Post.A(1); - m_Post.B(0); - m_Post.C(0); - m_Post.D(0); - m_Post.E(1); - m_Post.F(0); + m_Post.A(1); + m_Post.B(0); + m_Post.C(0); + m_Post.D(0); + m_Post.E(1); + m_Post.F(0); + + m_Wind[0] = 0; + m_Wind[1] = 0; + m_MotionFreq = 0; + } + else + { + m_Weight = EMPTYFIELD; + m_ColorSpeed = EMPTYFIELD; + m_Animate = EMPTYFIELD; + m_ColorX = EMPTYFIELD; + m_ColorY = EMPTYFIELD; + m_DirectColor = EMPTYFIELD; + m_Opacity = EMPTYFIELD; + + m_Affine.A(EMPTYFIELD); + m_Affine.B(EMPTYFIELD); + m_Affine.C(EMPTYFIELD); + m_Affine.D(EMPTYFIELD); + m_Affine.E(EMPTYFIELD); + m_Affine.F(EMPTYFIELD); + + m_Post.A(EMPTYFIELD); + m_Post.B(EMPTYFIELD); + m_Post.C(EMPTYFIELD); + m_Post.D(EMPTYFIELD); + m_Post.E(EMPTYFIELD); + m_Post.F(EMPTYFIELD); + + m_Wind[0] = EMPTYFIELD; + m_Wind[1] = EMPTYFIELD; + m_MotionFreq = EMPTYFIELD; + } - m_Wind[0] = 0; - m_Wind[1] = 0; - m_MotionFreq = 0; m_MotionFunc = MOTION_SIN; m_Motion.clear(); @@ -674,7 +712,12 @@ public: } //Why are we not using template with member var addr as arg here?//TODO -#define APPMOT(x) do { x += mot[i].x * Interpolater::MotionFuncs(func, freq * blend); } while (0) +#define APPMOT(x) \ + do \ + { \ + if (currentMot.x != EMPTYFIELD) \ + x += currentMot.x * Interpolater::MotionFuncs(func, freq * blend); \ + } while (0) /// /// Apply the motion functions from the passed in xform to this xform. @@ -683,15 +726,13 @@ public: /// The time blending value 0-1 void ApplyMotion(Xform& xform, T blend) { - Xform* mot = xform.m_Motion.data(); - //Loop over the motion elements and add their contribution to the original vals. for (size_t i = 0; i < xform.m_Motion.size(); i++) { //Original only pulls these from the first motion xform which is a bug. Want to pull it from each one. - Xform* currentMot = &xform.m_Motion[i]; - intmax_t freq = currentMot->m_MotionFreq; - eMotion func = currentMot->m_MotionFunc; + Xform& currentMot = xform.m_Motion[i]; + intmax_t freq = currentMot.m_MotionFreq; + eMotion func = currentMot.m_MotionFunc; //Clamp these to the appropriate range after all are applied. APPMOT(m_Weight); @@ -702,9 +743,9 @@ public: APPMOT(m_ColorSpeed); APPMOT(m_Animate); - for (size_t j = 0; j < currentMot->TotalVariationCount(); j++)//For each variation in the motion xform. + for (size_t j = 0; j < currentMot.TotalVariationCount(); j++)//For each variation in the motion xform. { - Variation* motVar = currentMot->GetVariation(j);//Get the variation, which may or may not be present in this xform. + Variation* motVar = currentMot.GetVariation(j);//Get the variation, which may or may not be present in this xform. ParametricVariation* motParVar = dynamic_cast*>(motVar); Variation* var = GetVariationById(motVar->VariationId());//See if the variation in the motion xform was present in the xform. @@ -752,7 +793,7 @@ public: //ClampRef(m_ColorY, 0, 1); ClampRef(m_DirectColor, 0, 1); ClampRef(m_Opacity, 0, 1);//Original didn't clamp these, but do it here for correctness. - ClampRef(m_ColorSpeed, 0, 1); + ClampRef(m_ColorSpeed, -1, 1); ClampGte0Ref(m_Weight); } diff --git a/Source/Ember/XmlToEmber.h b/Source/Ember/XmlToEmber.h index 88785c8..93ebbaa 100644 --- a/Source/Ember/XmlToEmber.h +++ b/Source/Ember/XmlToEmber.h @@ -1018,7 +1018,7 @@ private: { if (!Compare(motionNode->name, "motion")) { - Xform xform; + Xform xform(false);//Will only have valid values in fields parsed for motion, all others will be EMPTYFIELD. if (!ParseXform(motionNode, xform, true)) m_ErrorReport.push_back(string(loc) + " : Error parsing motion xform"); diff --git a/Source/EmberTester/EmberTester.cpp b/Source/EmberTester/EmberTester.cpp index 481604a..8d77a51 100644 --- a/Source/EmberTester/EmberTester.cpp +++ b/Source/EmberTester/EmberTester.cpp @@ -1956,12 +1956,12 @@ int _tmain(int argc, _TCHAR* argv[]) //std::complex cd, cd2; //cd2 = sin(cd); - /* + t.Tic(); TestCasting(); t.Toc("TestCasting()"); - t.Tic(); + /*t.Tic(); VariationList vlf; t.Toc("Creating VariationList");