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");