summaryrefslogtreecommitdiff
path: root/Runtime/Graphics/ParticleSystem/ParticleSystemCurves.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Runtime/Graphics/ParticleSystem/ParticleSystemCurves.cpp')
-rw-r--r--Runtime/Graphics/ParticleSystem/ParticleSystemCurves.cpp196
1 files changed, 196 insertions, 0 deletions
diff --git a/Runtime/Graphics/ParticleSystem/ParticleSystemCurves.cpp b/Runtime/Graphics/ParticleSystem/ParticleSystemCurves.cpp
new file mode 100644
index 0000000..3ac445c
--- /dev/null
+++ b/Runtime/Graphics/ParticleSystem/ParticleSystemCurves.cpp
@@ -0,0 +1,196 @@
+#include "UnityPrefix.h"
+#include "ParticleSystemCurves.h"
+#include "Runtime/Math/Polynomials.h"
+#include "Runtime/Math/Vector2.h"
+#include "Runtime/BaseClasses/ObjectDefines.h"
+#include "Runtime/Serialize/TransferFunctions/SerializeTransfer.h"
+
+// Calculates the min max range of an animation curve analytically
+static void CalculateCurveRangesValue(Vector2f& minMaxValue, const AnimationCurve& curve)
+{
+ const int keyCount = curve.GetKeyCount();
+ if (keyCount == 0)
+ return;
+
+ if (keyCount == 1)
+ {
+ CalculateMinMax(minMaxValue, curve.GetKey(0).value);
+ }
+ else
+ {
+ int segmentCount = keyCount - 1;
+ CalculateMinMax(minMaxValue, curve.GetKey(0).value);
+ for (int i = 0;i<segmentCount;i++)
+ {
+ DebugAssert(i+1 < keyCount);
+ AnimationCurve::Cache cache;
+ curve.CalculateCacheData(cache, i, i + 1, 0.0F);
+
+ // Differentiate polynomial
+ float a = 3.0f * cache.coeff[0];
+ float b = 2.0f * cache.coeff[1];
+ float c = 1.0f * cache.coeff[2];
+
+ const float start = curve.GetKey(i).time;
+ const float end = curve.GetKey(i+1).time;
+
+ float roots[2];
+ int numRoots = QuadraticPolynomialRootsGeneric(a, b, c, roots[0], roots[1]);
+ for(int r = 0; r < numRoots; r++)
+ if((roots[r] >= 0.0f) && ((roots[r] + start) < end))
+ CalculateMinMax(minMaxValue, Polynomial::EvalSegment(roots[r], cache.coeff));
+ CalculateMinMax(minMaxValue, Polynomial::EvalSegment(end-start, cache.coeff));
+ }
+ }
+}
+
+bool BuildCurves (MinMaxOptimizedPolyCurves& polyCurves, const MinMaxAnimationCurves& editorCurves, float scalar, short minMaxState)
+{
+ bool isOptimizedCurve = polyCurves.max.BuildOptimizedCurve(editorCurves.max, scalar);
+ if ((minMaxState != kMMCTwoCurves) && (minMaxState != kMMCTwoConstants))
+ isOptimizedCurve = isOptimizedCurve && polyCurves.min.BuildOptimizedCurve(editorCurves.max, scalar);
+ else
+ isOptimizedCurve = isOptimizedCurve && polyCurves.min.BuildOptimizedCurve(editorCurves.min, scalar);
+ return isOptimizedCurve;
+}
+
+void BuildCurves (MinMaxPolyCurves& polyCurves, const MinMaxAnimationCurves& editorCurves, float scalar, short minMaxState)
+{
+ polyCurves.max.BuildCurve(editorCurves.max, scalar);
+ if ((minMaxState != kMMCTwoCurves) && (minMaxState != kMMCTwoConstants))
+ polyCurves.min.BuildCurve(editorCurves.max, scalar);
+ else
+ polyCurves.min.BuildCurve(editorCurves.min, scalar);
+}
+
+bool CurvesSupportProcedural (const MinMaxAnimationCurves& editorCurves, short minMaxState)
+{
+ bool isValid = PolynomialCurve::IsValidCurve(editorCurves.max);
+ if ((minMaxState != kMMCTwoCurves) && (minMaxState != kMMCTwoConstants))
+ return isValid;
+ else
+ return isValid && PolynomialCurve::IsValidCurve(editorCurves.min);
+}
+
+
+void MinMaxOptimizedPolyCurves::Integrate ()
+{
+ max.Integrate ();
+ min.Integrate ();
+}
+
+void MinMaxOptimizedPolyCurves::DoubleIntegrate ()
+{
+ max.DoubleIntegrate ();
+ min.DoubleIntegrate ();
+}
+
+Vector2f MinMaxOptimizedPolyCurves::FindMinMaxIntegrated()
+{
+ Vector2f minRange = min.FindMinMaxIntegrated();
+ Vector2f maxRange = max.FindMinMaxIntegrated();
+ Vector2f result = Vector2f(std::min(minRange.x, maxRange.x), std::max(minRange.y, maxRange.y));
+ return result;
+}
+
+Vector2f MinMaxOptimizedPolyCurves::FindMinMaxDoubleIntegrated()
+{
+ Vector2f minRange = min.FindMinMaxDoubleIntegrated();
+ Vector2f maxRange = max.FindMinMaxDoubleIntegrated();
+ Vector2f result = Vector2f(std::min(minRange.x, maxRange.x), std::max(minRange.y, maxRange.y));
+ return result;
+}
+
+void MinMaxPolyCurves::Integrate ()
+{
+ max.Integrate ();
+ min.Integrate ();
+}
+
+void MinMaxPolyCurves::DoubleIntegrate ()
+{
+ max.DoubleIntegrate ();
+ min.DoubleIntegrate ();
+}
+
+Vector2f MinMaxPolyCurves::FindMinMaxIntegrated()
+{
+ Vector2f minRange = min.FindMinMaxIntegrated();
+ Vector2f maxRange = max.FindMinMaxIntegrated();
+ Vector2f result = Vector2f(std::min(minRange.x, maxRange.x), std::max(minRange.y, maxRange.y));
+ return result;
+}
+
+Vector2f MinMaxPolyCurves::FindMinMaxDoubleIntegrated()
+{
+ Vector2f minRange = min.FindMinMaxDoubleIntegrated();
+ Vector2f maxRange = max.FindMinMaxDoubleIntegrated();
+ Vector2f result = Vector2f(std::min(minRange.x, maxRange.x), std::max(minRange.y, maxRange.y));
+ return result;
+}
+
+MinMaxCurve::MinMaxCurve ()
+: scalar (1.0f)
+, minMaxState (kMMCScalar)
+, isOptimizedCurve(false)
+{
+ SetPolynomialCurveToValue (editorCurves.max, polyCurves.max, 1.0f);
+ SetPolynomialCurveToValue (editorCurves.min, polyCurves.min, 0.0f);
+}
+
+Vector2f MinMaxCurve::FindMinMax() const
+{
+ Vector2f result = Vector2f(std::numeric_limits<float>::infinity (), -std::numeric_limits<float>::infinity ());
+ CalculateCurveRangesValue(result, editorCurves.max);
+ if((minMaxState == kMMCTwoCurves) || (minMaxState == kMMCTwoConstants))
+ CalculateCurveRangesValue(result, editorCurves.min);
+ return result * GetScalar();
+}
+
+Vector2f MinMaxCurve::FindMinMaxIntegrated() const
+{
+ if(IsOptimized())
+ {
+ MinMaxOptimizedPolyCurves integrated = polyCurves;
+ integrated.Integrate();
+ return integrated.FindMinMaxIntegrated();
+ }
+ else
+ {
+ DebugAssert(CurvesSupportProcedural (editorCurves, minMaxState));
+ MinMaxPolyCurves integrated;
+ BuildCurves(integrated, editorCurves, GetScalar(), minMaxState);
+ integrated.Integrate();
+ return integrated.FindMinMaxIntegrated();
+ }
+}
+
+Vector2f MinMaxCurve::FindMinMaxDoubleIntegrated() const
+{
+ if(IsOptimized())
+ {
+ MinMaxOptimizedPolyCurves doubleIntegrated = polyCurves;
+ doubleIntegrated.DoubleIntegrate();
+ return doubleIntegrated.FindMinMaxDoubleIntegrated();
+ }
+ else
+ {
+ DebugAssert(CurvesSupportProcedural (editorCurves, minMaxState));
+ MinMaxPolyCurves doubleIntegrated;
+ BuildCurves(doubleIntegrated, editorCurves, GetScalar(), minMaxState);
+ doubleIntegrated.DoubleIntegrate();
+ return doubleIntegrated.FindMinMaxDoubleIntegrated();
+ }
+}
+
+template<class TransferFunction>
+void MinMaxCurve::Transfer (TransferFunction& transfer)
+{
+ transfer.Transfer (scalar, "scalar");
+ transfer.Transfer (editorCurves.max, "maxCurve");
+ transfer.Transfer (editorCurves.min, "minCurve");
+ TRANSFER (minMaxState); transfer.Align ();
+ if (transfer.IsReading ())
+ isOptimizedCurve = BuildCurves(polyCurves, editorCurves, scalar, minMaxState);
+}
+INSTANTIATE_TEMPLATE_TRANSFER(MinMaxCurve)