#pragma once

#include "VariationList.h"
#include "Interpolate.h"

/// <summary>
/// Xform class.
/// </summary>

namespace EmberNs
{
/// <summary>
/// Xform and Ember need each other, but each can't include the other.
/// So Ember includes this file, and Ember is declared as a forward declaration here.
/// </summary>
template <typename T> class Ember;

/// <summary>
/// If both polymorphism and templating are needed, uncomment this, fill it out and derive from it.
/// </summary>
//class EMBER_API XformBase
//{
//};

/// <summary>
/// An xform is a pre affine transform, a list of variations, and an optional final affine transform.
/// This is what gets applied to a point for each iteration.
/// Template argument expected to be float or double.
/// </summary>
template <typename T>
class EMBER_API Xform
{
public:
	/// <summary>
	/// 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.
	/// </summary>
	/// <param name="useDefaults">Use reasonable default if true, else use out of bounds values.</param>
	Xform(bool useDefaults = true)
	{
		Init(useDefaults);
	}

	/// <summary>
	/// Constructor that takes default arguments. Mostly used for testing.
	/// Post affine is defaulted to the identity matrix.
	/// </summary>
	/// <param name="density">The probability that this xform is chosen</param>
	/// <param name="colorX">The color index</param>
	/// <param name="colorSpeed">The color speed</param>
	/// <param name="opacity">The opacity</param>
	/// <param name="a">The a value of the pre affine transform</param>
	/// <param name="d">The d value of the pre affine transform</param>
	/// <param name="b">The b value of the pre affine transform</param>
	/// <param name="e">The e value of the pre affine transform</param>
	/// <param name="c">The c value of the pre affine transform</param>
	/// <param name="f">The f value of the pre affine transform</param>
	/// <param name="pa">The a value of the post affine transform. Default: 1.</param>
	/// <param name="pd">The d value of the post affine transform. Default: 0.</param>
	/// <param name="pb">The b value of the post affine transform. Default: 0.</param>
	/// <param name="pe">The e value of the post affine transform. Default: 1.</param>
	/// <param name="pc">The c value of the post affine transform. Default: 0.</param>
	/// <param name="pf">The f value of the post affine transform. Default: 0.</param>
	Xform(T weight, T colorX, T colorSpeed, T opacity,
		  T a, T d, T b, T e, T c, T f,
		  T pa = 1,
		  T pd = 0,
		  T pb = 0,
		  T pe = 1,
		  T pc = 0,
		  T pf = 0)
		: Xform()

	{
		m_Weight = weight;
		m_ColorX = colorX;
		m_ColorSpeed = colorSpeed;
		m_Opacity = opacity;
		m_Affine.A(a);
		m_Affine.B(b);
		m_Affine.C(c);
		m_Affine.D(d);
		m_Affine.E(e);
		m_Affine.F(f);
		m_Post.A(pa);
		m_Post.B(pb);
		m_Post.C(pc);
		m_Post.D(pd);
		m_Post.E(pe);
		m_Post.F(pf);
		m_HasPre = !m_Affine.IsID();
		m_HasPost = !m_Post.IsID();
		m_HasPreOrRegularVars = PreVariationCount() > 0 || VariationCount() > 0;
		CacheColorVals();//Init already called this, but must call again since color was assigned above.
	}

	/// <summary>
	/// Default copy constructor.
	/// </summary>
	/// <param name="xform">The Xform object to copy</param>
	Xform(const Xform<T>& xform)
		: m_ParentEmber(nullptr)//Hack.
	{
		Xform<T>::operator=<T>(xform);
	}

	/// <summary>
	/// Copy constructor to copy an Xform object of type U.
	/// </summary>
	/// <param name="xform">The Xform object to copy</param>
	template <typename U>
	Xform(const Xform<U>& xform)
		: m_ParentEmber(nullptr)//Hack.
	{
		Xform<T>::operator=<U>(xform);
	}

	/// <summary>
	/// Deletes each element of the variation vector and clears it.
	/// </summary>
	~Xform()
	{
		ClearAndDeleteVariations();
	}

	/// <summary>
	/// Default assignment operator.
	/// </summary>
	/// <param name="xform">The Xform object to copy</param>
	Xform<T>& operator = (const Xform<T>& xform)
	{
		if (this != &xform)
			Xform<T>::operator=<T>(xform);

		return *this;
	}

	/// <summary>
	/// Assignment operator to assign a Xform object of type U.
	/// This will delete all of the variations in the vector
	/// and repopulate it with copes of the variation in xform's vector.
	/// All other values are assigned directly.
	/// </summary>
	/// <param name="xform">The Xform object to copy.</param>
	/// <returns>Reference to updated self</returns>
	template <typename U>
	Xform<T>& operator = (const Xform<U>& xform)
	{
		m_Affine = xform.m_Affine;
		m_Post = xform.m_Post;
		m_Weight = static_cast<T>(xform.m_Weight);
		m_ColorX = static_cast<T>(xform.m_ColorX);
		m_ColorY = static_cast<T>(xform.m_ColorY);
		m_DirectColor = static_cast<T>(xform.m_DirectColor);
		m_ColorSpeed = static_cast<T>(xform.m_ColorSpeed);
		m_Animate = static_cast<T>(xform.m_Animate);
		m_AnimateOrigin = static_cast<T>(xform.m_AnimateOrigin);
		m_Opacity = static_cast<T>(xform.m_Opacity);
		CacheColorVals();
		m_HasPre = xform.HasPre();
		m_HasPost = xform.HasPost();
		m_HasPreOrRegularVars = xform.PreVariationCount() > 0 || xform.VariationCount() > 0;
		m_Wind[0] = static_cast<T>(xform.m_Wind[0]);
		m_Wind[1] = static_cast<T>(xform.m_Wind[1]);
		m_MotionFreq = static_cast<T>(xform.m_MotionFreq);
		m_MotionFunc = xform.m_MotionFunc;
		m_MotionOffset = static_cast<T>(xform.m_MotionOffset);
		ClearAndDeleteVariations();

		//Must manually add them via the AddVariation() function so that
		//the variation's m_IndexInXform member gets properly set to this.
		for (size_t i = 0; i < xform.TotalVariationCount(); i++)
		{
			Variation<T>* var = nullptr;

			if (Variation<U>* varOrig = xform.GetVariation(i))
			{
				varOrig->Copy(var);//Will convert from type U to type T.
				AddVariation(var);//Will internally call SetPrecalcFlags().
			}
		}

		if (TotalVariationCount() == 0)
			SetPrecalcFlags();

		//If this xform was already part of a different ember, then do not assign, else do.
		if (!m_ParentEmber && (typeid(T) == typeid(U)))
			m_ParentEmber = reinterpret_cast<Ember<T>*>(xform.ParentEmber());

		CopyCont(m_Xaos, xform.XaosVec());
		CopyCont(m_Motion, xform.m_Motion);
		m_Name = xform.m_Name;
		return *this;
	}

	/// <summary>
	/// 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.
	/// </summary>
	/// <param name="useDefaults">Use reasonable default if true, else use out of bounds values.</param>
	void Init(bool useDefaults = true)
	{
		static size_t count = 0;

		if (useDefaults)
		{
			m_Weight = 0;
			m_ColorSpeed = static_cast<T>(0.5);
			m_Animate = 1;
			m_AnimateOrigin = 0;
			m_ColorX = static_cast<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_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;
			m_MotionOffset = 0;
		}
		else
		{
			m_Weight = EMPTYFIELD;
			m_ColorSpeed = EMPTYFIELD;
			m_Animate = EMPTYFIELD;
			m_AnimateOrigin = 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_MotionOffset = EMPTYFIELD;
		}

		m_MotionFunc = eMotion::MOTION_SIN;
		m_Motion.clear();
		m_NeedPrecalcSumSquares = false;
		m_NeedPrecalcSqrtSumSquares = false;
		m_NeedPrecalcAngles = false;
		m_NeedPrecalcAtanXY = false;
		m_NeedPrecalcAtanYX = false;
		m_HasPre = false;
		m_HasPost = false;
		m_HasPreOrRegularVars = false;
		m_ParentEmber = nullptr;
		m_PreVariations.reserve(8);
		m_Variations.reserve(8);
		m_PostVariations.reserve(8);
		CacheColorVals();
		count++;
	}

	/// <summary>
	/// Add a pointer to a variation which will be deleted on destruction so the caller should not delete.
	/// It also checks if the variation is already present, in which case it doesn't add.
	/// If add, set all precalcs.
	/// </summary>
	/// <param name="variation">Pointer to a varation to add</param>
	/// <returns>True if the successful, else false.</returns>
	bool AddVariation(Variation<T>* variation)
	{
		if (variation && (GetVariationById(variation->VariationId()) == nullptr))
		{
			string name = variation->Name();
			bool pre = name.find("pre_") == 0;
			bool post = name.find("post_") == 0;
			vector<Variation<T>*>* vec;

			if (pre)
				vec = &m_PreVariations;
			else if (post)
				vec = &m_PostVariations;
			else
				vec = &m_Variations;

			vec->push_back(variation);

			//Flatten must always be last.
			for (size_t i = 0; i < vec->size(); i++)
			{
				if ((i != vec->size() - 1) && ((*vec)[i]->Name().find("flatten") != string::npos))
				{
					std::swap((*vec)[i], (*vec)[vec->size() - 1]);
					break;
				}
			}

			SetPrecalcFlags();
			return true;
		}

		return false;
	}

	/// <summary>
	/// Insert a pointer to a variation, at the specified location, which will be deleted on destruction so the caller should not delete.
	/// It also checks if the variation is already present, in which case it doesn't add.
	/// If add, set all precalcs.
	/// </summary>
	/// <param name="variation">Pointer to a varation to add</param>
	/// <param name="index">The index to insert at</param>
	/// <returns>True if the successful, else false.</returns>
	bool InsertVariation(Variation<T>* variation, size_t index)
	{
		if (variation && (GetVariationById(variation->VariationId()) == nullptr))
		{
			string name = variation->Name();
			bool pre = name.find("pre_") == 0;
			bool post = name.find("post_") == 0;
			vector<Variation<T>*>* vec;

			if (pre)
				vec = &m_PreVariations;
			else if (post)
				vec = &m_PostVariations;
			else
				vec = &m_Variations;

			vec->insert(vec->begin() + index, variation);

			//Flatten must always be last.
			for (size_t i = 0; i < vec->size(); i++)
			{
				if ((i != vec->size() - 1) && ((*vec)[i]->Name().find("flatten") != string::npos))
				{
					std::swap((*vec)[i], (*vec)[vec->size() - 1]);
					break;
				}
			}

			SetPrecalcFlags();
			return true;
		}

		return false;
	}

	/// <summary>
	/// Get a pointer to the variation at the specified index.
	/// </summary>
	/// <param name="index">The index in the list to retrieve</param>
	/// <returns>A pointer to the variation at the index if in range, else nullptr.</returns>
	Variation<T>* GetVariation(size_t index) const
	{
		size_t count = 0;
		Variation<T>* var = nullptr;
		const_cast<Xform<T>*>(this)->AllVarsFunc([&] (vector<Variation<T>*>& variations, bool & keepGoing)
		{
			for (size_t i = 0; i < variations.size(); i++, count++)
			{
				if (count == index)
				{
					var = variations[i];
					keepGoing = false;
					break;
				}
			}
		});
		return var;
	}

	/// <summary>
	/// Get a pointer to the variation with the specified ID.
	/// </summary>
	/// <param name="id">The ID to search for</param>
	/// <returns>A pointer to the variation if found, else nullptr.</returns>
	Variation<T>* GetVariationById(eVariationId id) const
	{
		Variation<T>* var = nullptr;
		const_cast<Xform<T>*>(this)->AllVarsFunc([&] (vector<Variation<T>*>& variations, bool & keepGoing)
		{
			for (auto v : variations)
			{
				if (v && v->VariationId() == id)
				{
					var = v;
					keepGoing = false;
					break;
				}
			}
		});
		return var;
	}

	/// <summary>
	/// Get a pointer to the variation with the specified name.
	/// </summary>
	/// <param name="name">The name to search for</param>
	/// <returns>A pointer to the variation if found, else nullptr.</returns>
	Variation<T>* GetVariationByName(const string& name) const
	{
		Variation<T>* var = nullptr;
		const_cast<Xform<T>*>(this)->AllVarsFunc([&] (vector<Variation<T>*>& variations, bool & keepGoing)
		{
			for (auto v : variations)
			{
				if (v && v->Name() == name)
				{
					var = v;
					keepGoing = false;
					break;
				}
			}
		});
		return var;
	}

	/// <summary>
	/// Get the index in the list of the variation pointer.
	/// Note this is searching for the exact pointer address and not the name or ID of the variation.
	/// </summary>
	/// <param name="var">A pointer to the variation to search for</param>
	/// <returns>The index of the variation if found, else -1</returns>
	intmax_t GetVariationIndex(Variation<T>* var) const
	{
		intmax_t count = 0, index = -1;
		const_cast<Xform<T>*>(this)->AllVarsFunc([&] (vector<Variation<T>*>& variations, bool & keepGoing)
		{
			for (size_t i = 0; i < variations.size(); i++, count++)
			{
				if (variations[i] == var)
				{
					index = count;
					keepGoing = false;
					break;
				}
			}
		});
		return index;
	}

	/// <summary>
	/// Delete the variation with the matching ID.
	/// Update precalcs if deletion successful.
	/// </summary>
	/// <param name="id">The ID to search for</param>
	/// <returns>True if deletion successful, else false.</returns>
	bool DeleteVariationById(eVariationId id)
	{
		bool found = false;
		AllVarsFunc([&] (vector<Variation<T>*>& variations, bool & keepGoing)
		{
			for (size_t i = 0; i < variations.size(); i++)
			{
				if (variations[i] && variations[i]->VariationId() == id)
				{
					delete variations[i];
					variations.erase(variations.begin() + i);
					found = true;
				}
			}
		});

		if (found)
			SetPrecalcFlags();

		return found;
	}

	/// <summary>
	/// Remove the variation with the matching ID, but instead of deleting it, return it.
	/// Update precalcs if deletion successful.
	/// </summary>
	/// <param name="id">The ID to search for</param>
	/// <returns>The variation if found, else nullptr.</returns>
	Variation<T>* RemoveVariationById(eVariationId id)
	{
		Variation<T>* var = nullptr;
		AllVarsFunc([&](vector<Variation<T>*>& variations, bool & keepGoing)
		{
			for (size_t i = 0; i < variations.size(); i++)
			{
				if (variations[i] && variations[i]->VariationId() == id)
				{
					var = variations[i];
					variations.erase(variations.begin() + i);
					keepGoing = false;
					break;
				}
			}
		});

		if (var)
			SetPrecalcFlags();

		return var;
	}

	/// <summary>
	/// Delete the motion elements.
	/// </summary>
	void DeleteMotionElements()
	{
		m_Motion.clear();
	}

	/// <summary>
	/// Delete all variations, clear the list and update precalc flags.
	/// </summary>
	void ClearAndDeleteVariations()
	{
		AllVarsFunc([&] (vector<Variation<T>*>& variations, bool & keepGoing) { ClearVec<Variation<T>>(variations); });
		SetPrecalcFlags();
	}

	/// <summary>
	/// Reset this xform to be totally empty by clearing all variations, resetting both affines to the
	/// identity matrix, clearing xaos, color, visibility, wind, animate and setting name
	/// to the empty string.
	/// Note that this also sets the parent ember to nullptr, so if this xform is reused after calling Clear(),
	/// the caller must reset the parent ember to whatever ember they add it to again.
	/// </summary>
	void Clear()
	{
		ClearAndDeleteVariations();
		DeleteMotionElements();
		m_Affine.MakeID();
		m_Post.MakeID();
		m_Xaos.clear();
		m_ParentEmber = nullptr;
		m_ColorSpeedCache = 0;
		m_OneMinusColorCache = 0;
		m_Opacity = 1;
		m_Animate = 0;
		m_AnimateOrigin = 0;
		m_Wind[0] = 0;
		m_Wind[1] = 0;
		m_Name = "";
	}

	/// <summary>
	/// Compute color cache values: color speed and one minus color speed.
	/// </summary>
	void CacheColorVals() noexcept
	{
		//Figure out which is right. //TODO.
		//m_ColorSpeedCache = m_ColorX * (1 - m_ColorSpeed) / 2;//Apo style.
		//m_OneMinusColorCache = (1 + m_ColorSpeed) / 2;
		m_ColorSpeedCache = m_ColorSpeed * m_ColorX;//Flam3 style.
		m_OneMinusColorCache = static_cast<T>(1) - m_ColorSpeed;
	}

	/// <summary>
	/// Return the xaos value at the specified index.
	/// If the index is out of range, return 1.
	/// This has the convenient effect that xaos is not present
	/// by default and only has a value if explicitly added.
	/// </summary>
	/// <param name="i">The xaos index to retrieve</param>
	/// <returns>The value at the index if in range, else 1.</returns>
	T Xaos(size_t i) const noexcept
	{
		return i < m_Xaos.size() ? m_Xaos[i] : 1;
	}

	/// <summary>
	/// Set the xaos value for a given xform index.
	/// If the index is out of range, a 1 value will be added
	/// to the xaos vector repeatedly until it's one less than the
	/// requested index in length, then finally add the specified value.
	/// </summary>
	/// <param name="i">The index to set</param>
	/// <param name="val">The xaos value to set it to</param>
	void SetXaos(size_t i, T val)
	{
		if (i < m_Xaos.size())
		{
			m_Xaos[i] = val;
		}
		else
		{
			while (m_Xaos.size() <= i)
				m_Xaos.push_back(1);

			m_Xaos[i] = val;
		}
	}

	/// <summary>
	/// Determine if any xaos value in the vector up to the xform count
	/// of the parent ember is anything other than 1.
	/// </summary>
	/// <returns>True if found, else false.</returns>
	bool XaosPresent() const noexcept
	{
		if (m_ParentEmber)
			for (size_t i = 0; i < m_Xaos.size(); i++)
				if (i < m_ParentEmber->XformCount())
					if (!IsClose<T>(m_Xaos[i], 1))
						return true;//If at least one entry is not equal to 1, then xaos is present.

		return false;
	}

	/// <summary>
	/// Truncate the xaos vector to match the xform count of the parent ember.
	/// </summary>
	void TruncateXaos()
	{
		if (m_ParentEmber)
			while (m_Xaos.size() > m_ParentEmber->XformCount())
				m_Xaos.pop_back();
	}

	/// <summary>
	/// Remove all xaos from this xform.
	/// </summary>
	void ClearXaos()
	{
		m_Xaos.clear();
	}

	/// <summary>
	/// Normalize the variation weights.
	/// </summary>
	void NormalizeVariationWeights()
	{
		AllVarsFunc([&] (vector<Variation<T>*>& variations, bool & keepGoing)
		{
			T norm = 0;

			for (auto var : variations) norm += var->m_Weight;

			for (auto var : variations) var->m_Weight /= Zeps(norm);//Ensure a divide by zero never happens.
		});
	}

	/// <summary>
	/// Applies this xform to the point passed in and saves the result in the out point.
	/// It's important to understand what happens here since it's the inner core of the algorithm.
	/// See the internal comments for step by step details.
	/// </summary>
	/// <param name="inPoint">The initial point from the previous iteration</param>
	/// <param name="outPoint">The output point</param>
	/// <param name="rand">The random context to use</param>
	/// <returns>True if a bad value was calculated, else false.</returns>
	bool Apply(Point<T>* inPoint, Point<T>* outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand)
	{
		size_t i;
		//This must be local, rather than a member, because this function can be called
		//from multiple threads. If it were a member, they'd be clobbering each others' values.
		IteratorHelper<T> iterHelper;
		//Calculate the color coordinate/index in the palette to look up later when accumulating the output point
		//to the histogram. Calculate this value by interpolating between the index value of the
		//last iteration with the one specified in this xform. Note that some cached values are used
		//to reduce the amount of processing.
		outPoint->m_Opacity = m_Opacity;
		iterHelper.m_Color.x = outPoint->m_ColorX = m_ColorSpeedCache + (m_OneMinusColorCache * inPoint->m_ColorX);

		//Compute the pre affine portion of the transform.
		//These x, y values are what get passed to the variations below.
		//Note that they are not changed after this, except in the case of pre_ variations.
		if (m_HasPre)
		{
			iterHelper.m_TransX = (m_Affine.A() * inPoint->m_X) + (m_Affine.B() * inPoint->m_Y) + m_Affine.C();
			iterHelper.m_TransY = (m_Affine.D() * inPoint->m_X) + (m_Affine.E() * inPoint->m_Y) + m_Affine.F();
		}
		else
		{
			iterHelper.m_TransX = inPoint->m_X;
			iterHelper.m_TransY = inPoint->m_Y;
		}

		iterHelper.m_TransZ = inPoint->m_Z;

		if (m_HasPreOrRegularVars)
		{
			//Apply pre_ variations, these don't affect outPoint, only iterHelper.m_TransX, Y, Z.
			for (i = 0; i < PreVariationCount(); i++)
			{
				iterHelper.In.x = iterHelper.m_TransX;//Read must be done before every pre variation because transX/Y are changing.
				iterHelper.In.y = iterHelper.m_TransY;
				iterHelper.In.z = iterHelper.m_TransZ;
				m_PreVariations[i]->PrePostPrecalcHelper(iterHelper);//Apply per-variation precalc, the second parameter is unused for pre variations.
				m_PreVariations[i]->Func(iterHelper, *outPoint, rand);
				WritePre(iterHelper, m_PreVariations[i]->AssignType());
			}

			if (VariationCount() > 0)
			{
				//The original calculates sumsq and sumsqrt every time, regardless if they're used or not.
				//With Precalc(), only calculate those values if they're needed.
				Precalc(iterHelper);//Only need per-xform precalc with regular variations.
				iterHelper.In.x = iterHelper.m_TransX;//Only need to read once with regular variations, because transX/Y are fixed.
				iterHelper.In.y = iterHelper.m_TransY;
				iterHelper.In.z = iterHelper.m_TransZ;
				//Since these get summed, initialize them to zero.
				outPoint->m_X = outPoint->m_Y = outPoint->m_Z = 0;

				//Apply variations to the transformed points, accumulating each time, and store the final value in outPoint.
				//Using a virtual function is about 3% faster than using a large case statement like the original did.
				//Although research says that using virtual functions is slow, experience says otherwise. They execute
				//with the exact same speed as both regular and static member functions.
				for (i = 0; i < VariationCount(); i++)
				{
					m_Variations[i]->Func(iterHelper, *outPoint, rand);
					outPoint->m_X += iterHelper.Out.x;
					outPoint->m_Y += iterHelper.Out.y;
					outPoint->m_Z += iterHelper.Out.z;
				}
			}
			else//Only pre variations are present, no regular ones, so assign the affine transformed points directly to the output points.
			{
				outPoint->m_X = iterHelper.m_TransX;
				outPoint->m_Y = iterHelper.m_TransY;
				outPoint->m_Z = iterHelper.m_TransZ;
			}
		}
		//Return the affine transformed points if no variations are present.
		//Note this differs from flam3, which would just return zero in that scenario.
		else
		{
			//There are no variations, so the affine transformed points can be assigned directly to the output points.
			outPoint->m_X = 0;//(m_Affine.A() * inPoint->m_X) + (m_Affine.B() * inPoint->m_Y) + m_Affine.C();
			outPoint->m_Y = 0;//(m_Affine.D() * inPoint->m_X) + (m_Affine.E() * inPoint->m_Y) + m_Affine.F();
			outPoint->m_Z = 0;//inPoint->m_Z;
		}

		//Apply post variations, these will modify outPoint.
		for (i = 0; i < PostVariationCount(); i++)
		{
			iterHelper.In.x = outPoint->m_X;//Read must be done before every post variation because the out point is changing.
			iterHelper.In.y = outPoint->m_Y;
			iterHelper.In.z = outPoint->m_Z;
			m_PostVariations[i]->PrePostPrecalcHelper(iterHelper);//Apply per-variation precalc.
			m_PostVariations[i]->Func(iterHelper, *outPoint, rand);
			WritePost(iterHelper, *outPoint, m_PostVariations[i]->AssignType());
		}

		//Optionally apply the post affine transform if it's present.
		if (m_HasPost)
		{
			T postX = outPoint->m_X;
			outPoint->m_X = (m_Post.A() * postX) + (m_Post.B() * outPoint->m_Y) + m_Post.C();
			outPoint->m_Y = (m_Post.D() * postX) + (m_Post.E() * outPoint->m_Y) + m_Post.F();
		}

		outPoint->m_ColorX = iterHelper.m_Color.x + m_DirectColor * (outPoint->m_ColorX - iterHelper.m_Color.x);

		if (std::isnan(outPoint->m_ColorX))
			outPoint->m_ColorX = 0;

		//Has the trajectory of x or y gone either to infinity, or too close to zero?
		return BadVal(outPoint->m_X) || BadVal(outPoint->m_Y)/* || BadVal(outPoint->m_Z)*/;
	}

//Why are we not using template with member var addr as arg here?//TODO
#define APPMOT(x) \
	do \
	{ \
		if (currentMot.x != EMPTYFIELD) \
			x += currentMot.x * Interpolater<T>::MotionFuncs(func, freq * (blend + offset)); \
	} while (0)

	/// <summary>
	/// Apply the motion functions from the passed in xform to this xform.
	/// </summary>
	/// <param name="xform">The xform containing the motion functions</param>
	/// <param name="blend">The time blending value 0-1</param>
	void ApplyMotion(Xform<T>& xform, T blend)
	{
		//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.
			auto& currentMot = xform.m_Motion[i];
			auto freq = currentMot.m_MotionFreq;
			auto func = currentMot.m_MotionFunc;
			auto offset = currentMot.m_MotionOffset;
			auto cleanOffset = offset != EMPTYFIELD ? offset : 0;
			//Clamp these to the appropriate range after all are applied.
			APPMOT(m_Weight);
			APPMOT(m_ColorX);
			//APPMOT(m_ColorY);
			APPMOT(m_DirectColor);
			APPMOT(m_Opacity);
			APPMOT(m_ColorSpeed);
			APPMOT(m_Animate);
			APPMOT(m_AnimateOrigin);

			for (size_t j = 0; j < currentMot.TotalVariationCount(); j++)//For each variation in the motion xform.
			{
				Variation<T>* motVar = currentMot.GetVariation(j);//Get the variation, which may or may not be present in this xform.
				ParametricVariation<T>* motParVar = dynamic_cast<ParametricVariation<T>*>(motVar);
				Variation<T>* var = GetVariationById(motVar->VariationId());//See if the variation in the motion xform was present in the xform.

				if (!var)//It wasn't present, so add it and set the weight.
				{
					Variation<T>* newVar = motVar->Copy();
					newVar->m_Weight = motVar->m_Weight * Interpolater<T>::MotionFuncs(func, freq * (blend + cleanOffset));

					if (AddVariation(newVar))
						var = newVar;//Use this below for params.
					else
						delete newVar;
				}
				else//It was present, so apply the motion func to the weight.
				{
					var->m_Weight += motVar->m_Weight * Interpolater<T>::MotionFuncs(func, freq * (blend + cleanOffset));
				}

				//At this point, we've added if needed, or just applied the motion func to the weight.
				//Now apply the motion func to the params if needed.
				if (var && motParVar)
				{
					auto parVar = dynamic_cast<ParametricVariation<T>*>(var);
					auto params = parVar->Params();
					auto motParams = motParVar->Params();

					for (size_t k = 0; k < motParVar->ParamCount(); k++)
					{
						if (!motParams[k].IsPrecalc())
							*(params[k].Param()) += motParams[k].ParamVal() * Interpolater<T>::MotionFuncs(func, freq * (blend + cleanOffset));
					}
				}
			}

			for (glm::length_t j = 0; j < 2; j++)
			{
				for (glm::length_t k = 0; k < 3; k++)
				{
					APPMOT(m_Affine.m_Mat[j][k]);
					APPMOT(m_Post.m_Mat[j][k]);
				}
			}
		}

		//Make sure certain params are within reasonable bounds.
		ClampRef<T>(m_ColorX, 0, 1);
		//ClampRef<T>(m_ColorY, 0, 1);
		ClampRef<T>(m_DirectColor, 0, 1);
		ClampRef<T>(m_Opacity, 0, 1);//Original didn't clamp these, but do it here for correctness.
		ClampRef<T>(m_ColorSpeed, -1, 1);
		ClampGte0Ref<T>(m_Weight);
	}

	/// <summary>
	/// Accessors.
	/// The precalc flags are duplicated in each variation. Each value here
	/// is true if any of the variations need it precalculated.
	/// </summary>
	inline bool NeedPrecalcSumSquares()     const noexcept { return m_NeedPrecalcSumSquares; }
	inline bool NeedPrecalcSqrtSumSquares() const noexcept { return m_NeedPrecalcSqrtSumSquares; }
	inline bool NeedPrecalcAngles()         const noexcept { return m_NeedPrecalcAngles; }
	inline bool NeedPrecalcAtanXY()         const noexcept { return m_NeedPrecalcAtanXY; }
	inline bool NeedPrecalcAtanYX()         const noexcept { return m_NeedPrecalcAtanYX; }
	inline bool NeedAnyPrecalc()            const noexcept { return NeedPrecalcSumSquares() || NeedPrecalcSqrtSumSquares() || NeedPrecalcAngles() || NeedPrecalcAtanXY() || NeedPrecalcAtanYX(); }
	bool HasPre() const noexcept { return m_HasPre; }
	bool HasPost() const noexcept { return m_HasPost; }
	size_t PreVariationCount()   const noexcept { return m_PreVariations.size(); }
	size_t VariationCount()      const noexcept { return m_Variations.size(); }
	size_t PostVariationCount()  const noexcept { return m_PostVariations.size(); }
	size_t TotalVariationCount() const noexcept { return PreVariationCount() + VariationCount() + PostVariationCount(); }
	bool Empty() const noexcept { return TotalVariationCount() == 0 && m_Affine.IsID(); }//Use this instead of padding like the original did.
	T ColorSpeedCache() const noexcept { return m_ColorSpeedCache; }
	T OneMinusColorCache() const noexcept { return m_OneMinusColorCache; }
	const vector<T>& XaosVec() const noexcept { return m_Xaos; }
	Ember<T>* ParentEmber() const noexcept { return m_ParentEmber; }
	void ParentEmber(Ember<T>* ember) { m_ParentEmber = ember; }
	intmax_t IndexInParentEmber() const noexcept { return m_ParentEmber ? m_ParentEmber->GetTotalXformIndex(const_cast<Xform<T>*>(this)) : -1; }

	/// <summary>
	/// Set the precalc flags based on whether any variation in the vector needs them.
	/// Also call Precalc() virtual function on each variation, which will setup any needed
	/// precalcs in parametric variations.
	/// Set the parent xform of each variation to this.
	/// </summary>
	void SetPrecalcFlags()
	{
		m_NeedPrecalcSumSquares = false;
		m_NeedPrecalcSqrtSumSquares = false;
		m_NeedPrecalcAngles = false;
		m_NeedPrecalcAtanXY = false;
		m_NeedPrecalcAtanYX = false;
		m_HasPre = !m_Affine.IsID();
		m_HasPost = !m_Post.IsID();
		m_HasPreOrRegularVars = PreVariationCount() > 0 || VariationCount() > 0;

		//Only set precalcs for regular variations, they work differently for pre and post.
		for (auto var : m_Variations)
		{
			if (var->NeedPrecalcSumSquares())
				m_NeedPrecalcSumSquares = true;

			if (var->NeedPrecalcSqrtSumSquares())
				m_NeedPrecalcSqrtSumSquares = true;

			if (var->NeedPrecalcAngles())
				m_NeedPrecalcAngles = true;

			if (var->NeedPrecalcAtanXY())
				m_NeedPrecalcAtanXY = true;

			if (var->NeedPrecalcAtanYX())
				m_NeedPrecalcAtanYX = true;
		}

		AllVarsFunc([&] (vector<Variation<T>*>& variations, bool & keepGoing)
		{
			for (auto var : variations)
			{
				var->ParentXform(this);
				var->Precalc();
			}
		});
	}

	/// <summary>
	/// Based on the precalc flags determined in SetPrecalcFlags(), do the appropriate precalcs.
	/// </summary>
	/// <param name="helper">The iterator helper to store the precalculated values in</param>
	void Precalc(IteratorHelper<T>& helper)
	{
		if (m_NeedPrecalcSumSquares)
		{
			helper.m_PrecalcSumSquares = SQR(helper.m_TransX) + SQR(helper.m_TransY);

			if (m_NeedPrecalcSqrtSumSquares)
			{
				helper.m_PrecalcSqrtSumSquares = std::sqrt(helper.m_PrecalcSumSquares);

				if (m_NeedPrecalcAngles)
				{
					helper.m_PrecalcCosa = helper.m_TransX / Zeps(helper.m_PrecalcSqrtSumSquares);
					helper.m_PrecalcSina = helper.m_TransY / Zeps(helper.m_PrecalcSqrtSumSquares);
				}
			}
		}

		if (m_NeedPrecalcAtanXY)
			helper.m_PrecalcAtanxy = std::atan2(helper.m_TransX, helper.m_TransY);

		if (m_NeedPrecalcAtanYX)
			helper.m_PrecalcAtanyx = std::atan2(helper.m_TransY, helper.m_TransX);
	}

	/// <summary>
	/// Flatten this xform by adding a flatten variation if none is present, and if none of the
	/// variations or parameters in the vector are present.
	/// </summary>
	/// <param name="names">Vector of variation and parameter names that inhibit flattening</param>
	/// <returns>True if flatten was added, false if it already was present or if at least one of the specified variations or parameters were present.</returns>
	bool Flatten(vector<string>& names)
	{
		bool shouldFlatten = true;
		auto vl = VariationList<T>::Instance();

		if (GetVariationById(eVariationId::VAR_FLATTEN) == nullptr)
		{
			AllVarsFunc([&] (vector<Variation<T>*>& variations, bool & keepGoing)
			{
				for (auto var : variations)
				{
					if (var->m_Weight != 0)//This should never happen, but just to be safe.
					{
						if (FindIf(names, [&] (const string& s) -> bool { return !_stricmp(s.c_str(), var->Name().c_str()); }))  //If any variation is present, don't flatten.
						{
							shouldFlatten = false;
							keepGoing = false;
							break;
						}
					}

					//Now traverse the parameters for this variation.
					if (auto parVar = dynamic_cast<ParametricVariation<T>*>(var))//If any parametric variation parameter is present and non-zero, don't flatten.
					{
						for (auto& s : names)
						{
							if (parVar->GetParamVal(s.c_str()) != 0)
							{
								shouldFlatten = false;
								keepGoing = false;
								break;
							}
						}
					}
				}
			});

			if (shouldFlatten)//Flatten was not present and neither was any variation name or parameter in the list.
			{
				auto varflatten = vl->GetVariationCopy(eVariationId::VAR_FLATTEN);

				if (!AddVariation(varflatten))
				{
					delete varflatten;
					return false;
				}

				return true;
			}
		}

		return false;
	}

	/// <summary>
	/// Generate the OpenCL string for reading input values to
	/// be passed to a variation.
	/// </summary>
	/// <param name="varType">Type of the variation these values will be passed to.</param>
	/// <returns>The OpenCL string</returns>
	string ReadOpenCLString(eVariationType varType)
	{
		string s;

		switch (varType)
		{
			case eVariationType::VARTYPE_REG:
			case eVariationType::VARTYPE_PRE:
				s =
					"\tvIn.x = transX;\n"
					"\tvIn.y = transY;\n"
					"\tvIn.z = transZ;\n";
				break;

			case eVariationType::VARTYPE_POST:
			default:
				s =
					"\tvIn.x = outPoint->m_X;\n"
					"\tvIn.y = outPoint->m_Y;\n"
					"\tvIn.z = outPoint->m_Z;\n";
				break;
		}

		return s;
	}

	/// <summary>
	/// Assing output values from the result of a pre variation.
	/// </summary>
	/// <param name="helper">The helper to store the output values in</param>
	/// <param name="assignType">The type of assignment this variation uses, assign or sum.</param>
	inline void WritePre(IteratorHelper<T>& helper, eVariationAssignType assignType)
	{
		switch (assignType)
		{
			case eVariationAssignType::ASSIGNTYPE_SET:
			{
				helper.m_TransX = helper.Out.x;
				helper.m_TransY = helper.Out.y;
				helper.m_TransZ = helper.Out.z;
				break;
			}

			case eVariationAssignType::ASSIGNTYPE_SUM:
			default:
			{
				helper.m_TransX += helper.Out.x;
				helper.m_TransY += helper.Out.y;
				helper.m_TransZ += helper.Out.z;
				break;
			}
		}
	}

	/// <summary>
	/// Assing output values from the result of a post variation.
	/// </summary>
	/// <param name="helper">The helper to store the output values in</param>
	/// <param name="assignType">The type of assignment this variation uses, assign or sum.</param>
	inline void WritePost(IteratorHelper<T>& helper, Point<T>& outPoint, eVariationAssignType assignType) noexcept
	{
		switch (assignType)
		{
			case eVariationAssignType::ASSIGNTYPE_SET:
			{
				outPoint.m_X = helper.Out.x;
				outPoint.m_Y = helper.Out.y;
				outPoint.m_Z = helper.Out.z;
				break;
			}

			case eVariationAssignType::ASSIGNTYPE_SUM:
			default:
			{
				outPoint.m_X += helper.Out.x;
				outPoint.m_Y += helper.Out.y;
				outPoint.m_Z += helper.Out.z;
				break;
			}
		}
	}

	/// <summary>
	/// Generate the OpenCL string for writing output values from a call to a variation.
	/// </summary>
	/// <param name="varType">The type of variation these values were calculated from, pre, reg or post.</param>
	/// <param name="assignType">The type of assignment used by the variation these values were calculated from, assign or sum.</param>
	/// <returns>The OpenCL string</returns>
	string WriteOpenCLString(eVariationType varType, eVariationAssignType assignType)
	{
		string s;

		switch (varType)
		{
			case eVariationType::VARTYPE_REG:
			{
				s =
					"\toutPoint->m_X += vOut.x;\n"
					"\toutPoint->m_Y += vOut.y;\n"
					"\toutPoint->m_Z += vOut.z;\n";
				break;
			}

			case eVariationType::VARTYPE_PRE:
			{
				switch (assignType)
				{
					case eVariationAssignType::ASSIGNTYPE_SET:
					{
						s =
							"\ttransX = vOut.x;\n"
							"\ttransY = vOut.y;\n"
							"\ttransZ = vOut.z;\n";
						break;
					}

					case eVariationAssignType::ASSIGNTYPE_SUM:
					default:
					{
						s =
							"\ttransX += vOut.x;\n"
							"\ttransY += vOut.y;\n"
							"\ttransZ += vOut.z;\n";
						break;
					}
				}

				break;
			}

			case eVariationType::VARTYPE_POST:
			default:
			{
				switch (assignType)
				{
					case eVariationAssignType::ASSIGNTYPE_SET:
					{
						s =
							"\toutPoint->m_X = vOut.x;\n"
							"\toutPoint->m_Y = vOut.y;\n"
							"\toutPoint->m_Z = vOut.z;\n";
						break;
					}

					case eVariationAssignType::ASSIGNTYPE_SUM:
					default:
					{
						s =
							"\toutPoint->m_X += vOut.x;\n"
							"\toutPoint->m_Y += vOut.y;\n"
							"\toutPoint->m_Z += vOut.z;\n";
						break;
					}
				}

				break;
			}
		}

		return s;
	}

	/// <summary>
	/// Return a string representation of this xform.
	/// It will include all pre affine values, and optionally post affine values if present.
	/// Various variables, all variations as strings and xaos values if present.
	/// </summary>
	/// <returns>The string representation of this xform</returns>
	string ToString() const
	{
		ostringstream ss;
		ss << "A: " << m_Affine.A() << " "
		   << "B: " << m_Affine.B() << " "
		   << "C: " << m_Affine.C() << " "
		   << "D: " << m_Affine.D() << " "
		   << "E: " << m_Affine.E() << " "
		   << "F: " << m_Affine.F() << " \n";

		if (m_HasPost)
		{
			ss << "Post A: " << m_Post.A() << " "
			   << "Post B: " << m_Post.B() << " "
			   << "Post C: " << m_Post.C() << " "
			   << "Post D: " << m_Post.D() << " "
			   << "Post E: " << m_Post.E() << " "
			   << "Post F: " << m_Post.F() << " \n";
		}

		ss << "Weight: " << m_Weight;
		ss << "\nColorX: " << m_ColorX;
		ss << "\nColorY: " << m_ColorY;
		ss << "\nDirect Color: " << m_DirectColor;
		ss << "\nColor Speed: " << m_ColorSpeed;
		ss << "\nAnimate Local Rotation: " << m_Animate;
		ss << "\nAnimate Origin Rotation: " << m_AnimateOrigin;
		ss << "\nOpacity: " << m_Opacity;
		ss << "\nWind: " << m_Wind[0] << ", " << m_Wind[1];
		ss << "\nMotion Frequency: " << m_MotionFreq;
		ss << "\nMotion Func: " << m_MotionFunc;
		ss << "\nMotion Offset: " << m_MotionOffset;
		const_cast<Xform<T>*>(this)->AllVarsFunc([&] (vector<Variation<T>*>& variations, bool & keepGoing)
		{
			for (auto var : variations)
				ss << var->ToString() << "\n";

			ss << "\n";
		});

		if (XaosPresent())
		{
			for (auto xaos : m_Xaos)
				ss << xaos << " ";

			ss << "\n";
		}

		return ss.str();
	}

	/// <summary>
	/// Members are listed in the exact order they are used in Apply() to make them
	/// as cache efficient as possible. Not all are public, so there is repeated public/private
	/// access specifiers.
	/// </summary>

private:
	bool m_HasPreOrRegularVars;//Whethere there are any pre or regular variations present.

public:
	//Color coordinates for this function. This is the index into the palette used to look up a color and add to the histogram for each iter.
	//The original only allows for an x coord. Will eventually allow for a y coord like Fractron for 2D palettes.
	T m_ColorX, m_ColorY;

private:
	T m_ColorSpeedCache;//Cache of m_ColorSpeed * m_ColorX. Need to recalc cache values whenever anything relating to color is set. Made private because one affects the other.
	T m_OneMinusColorCache;//Cache of 1 - m_ColorSpeedCache.

public:
	//Coefficients for the affine portion of the transform.
	//Discussed on page 3 of the paper:
	//Fi(x, y) = (aix + biy + ci, dix + eiy + fi)
	Affine2D<T> m_Affine;

private:
	vector<Variation<T>*> m_PreVariations;//The list of pre variations to call when applying this xform.
	vector<Variation<T>*> m_Variations;//The list of variations to call when applying this xform.
	bool m_HasPre;//Whether a pre affine transform is present.
	bool m_HasPost;//Whether a post affine transform is present.

public:
	//Coefficients for the affine portion of the post transform.
	//Discussed on page 5 of the paper:
	//Pi(x, y) = (αix + βiy + γi, δix + ǫiy + ζi).
	Affine2D<T> m_Post;

private:
	vector<Variation<T>*> m_PostVariations;//The list of post variations to call when applying this xform.

public:
	T m_DirectColor;//Used with direct color variations.

	//Probability that this function is chosen. Can be greater than 1.
	//Discussed on page 4 of the paper:
	//Probability wi.
	T m_Weight;

	//Scaling factor on color added to current iteration, also known as color weight. Normally defaults to 0.5.
	//Discussed on page 9 of the paper with a hard coded default value of 0.5:
	//C = (C + Ci) * m_ColorSpeed.
	T m_ColorSpeed;
	T m_Opacity;//How much of this xform is seen. Range: 0.0 (invisible) - 1.0 (totally visible).
	T m_Animate;//Whether or not this xform rotates around its center during animation. 0 means stationary, > 0 means rotate. Use T instead of bool so it can be interpolated.
	T m_AnimateOrigin;//Same, but rotate around the global origin.
	T m_Wind[2];
	eMotion m_MotionFunc;
	T m_MotionFreq;
	T m_MotionOffset;
	vector<Xform<T>> m_Motion;
	string m_Name;

private:
	/// <summary>
	/// Perform an operation on all variation vectors.
	/// The operation is supplied in the func parameter.
	/// To stop performing the operation on vectors after the current one,
	/// set the keepGoing parameter to false;
	/// </summary>
	/// <param name="func">The function to call for each variation vector.</param>
	void AllVarsFunc(std::function<void (vector<Variation<T>*>&, bool&)> func)
	{
		bool keepGoing = true;
		func(m_PreVariations, keepGoing);

		if (keepGoing)
			func(m_Variations, keepGoing);

		if (keepGoing)
			func(m_PostVariations, keepGoing);
	}

	vector<T> m_Xaos;//Xaos vector which affects the probability that this xform is chosen. Usually empty.
	Ember<T>* m_ParentEmber;//The parent ember that contains this xform.
	bool m_NeedPrecalcSumSquares;//Whether any variation uses the precalc sum squares value in its calculations.
	bool m_NeedPrecalcSqrtSumSquares;//Whether any variation uses the sqrt precalc sum squares value in its calculations.
	bool m_NeedPrecalcAngles;//Whether any variation uses the precalc sin and cos values in its calculations.
	bool m_NeedPrecalcAtanXY;//Whether any variation uses the precalc atan XY value in its calculations.
	bool m_NeedPrecalcAtanYX;//Whether any variation uses the precalc atan YX value in its calculations.
};
}