mirror of
				https://bitbucket.org/mfeemster/fractorium.git
				synced 2025-11-04 02:00:31 -05:00 
			
		
		
		
	--User changes
-Allow locking of the scale at which affine circles are displayed. -Allow user to toggle whether xform will be animated when generating sequences. Also show the animate value when loading. --Code changes -More conversion to C++11 style code. -Add another value to the eXformUpdate enum called UPDATE_CURRENT_AND_SELECTED in anticipation of future work. -Remove some old #defines.
This commit is contained in:
		@ -112,6 +112,22 @@ typename v2T Affine2D<T>::operator * (const v2T& v)
 | 
				
			|||||||
	return TransformVector(v);
 | 
						return TransformVector(v);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Return a copy of the object with all values A-F scaled by the specified amount.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					/// <param name="amount">The amount to scale by</param>
 | 
				
			||||||
 | 
					/// <returns>A new Affine2D which a scaled copy of this instance</returns>
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					Affine2D<T> Affine2D<T>:: operator * (const T& t)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return Affine2D<T>(A() * t,
 | 
				
			||||||
 | 
										   D() * t,
 | 
				
			||||||
 | 
										   B() * t,
 | 
				
			||||||
 | 
										   E() * t,
 | 
				
			||||||
 | 
										   C() * t,
 | 
				
			||||||
 | 
										   F() * t);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
/// Make this affine transform the identity matrix.
 | 
					/// Make this affine transform the identity matrix.
 | 
				
			||||||
/// A and E = 1, all else 0.
 | 
					/// A and E = 1, all else 0.
 | 
				
			||||||
@ -172,6 +188,21 @@ bool Affine2D<T>::IsEmpty() const
 | 
				
			|||||||
		   (IsClose<T>(F(), EMPTYFIELD));
 | 
							   (IsClose<T>(F(), EMPTYFIELD));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Scales all values A-F by the specified amount.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					/// <param name="amount">The amount to scale by</param>
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					void Affine2D<T>::Scale(T amount)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						A(A() * amount);
 | 
				
			||||||
 | 
						B(B() * amount);
 | 
				
			||||||
 | 
						C(C() * amount);
 | 
				
			||||||
 | 
						D(D() * amount);
 | 
				
			||||||
 | 
						E(E() * amount);
 | 
				
			||||||
 | 
						F(F() * amount);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
/// Rotate this affine transform around its origin by the specified angle in degrees.
 | 
					/// Rotate this affine transform around its origin by the specified angle in degrees.
 | 
				
			||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
@ -181,7 +212,6 @@ void Affine2D<T>::Rotate(T angle)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	m4T origMat4 = ToMat4ColMajor(true);//Must center and use column major for glm to work.
 | 
						m4T origMat4 = ToMat4ColMajor(true);//Must center and use column major for glm to work.
 | 
				
			||||||
	m4T newMat4 = glm::rotate(origMat4, angle * DEG_2_RAD_T, v3T(0, 0, 1));//Assuming only rotating around z.
 | 
						m4T newMat4 = glm::rotate(origMat4, angle * DEG_2_RAD_T, v3T(0, 0, 1));//Assuming only rotating around z.
 | 
				
			||||||
 | 
					 | 
				
			||||||
	A(newMat4[0][0]);//Use direct assignments instead of constructor to skip assigning C and F.
 | 
						A(newMat4[0][0]);//Use direct assignments instead of constructor to skip assigning C and F.
 | 
				
			||||||
	B(newMat4[0][1]);
 | 
						B(newMat4[0][1]);
 | 
				
			||||||
	D(newMat4[1][0]);
 | 
						D(newMat4[1][0]);
 | 
				
			||||||
@ -206,7 +236,6 @@ template <typename T>
 | 
				
			|||||||
void Affine2D<T>::RotateScaleXTo(const v2T& v)
 | 
					void Affine2D<T>::RotateScaleXTo(const v2T& v)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Affine2D<T> rs = CalcRotateScale(X(), v);
 | 
						Affine2D<T> rs = CalcRotateScale(X(), v);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	X(rs.TransformNormal(X()));
 | 
						X(rs.TransformNormal(X()));
 | 
				
			||||||
	Y(rs.TransformNormal(Y()));
 | 
						Y(rs.TransformNormal(Y()));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -219,7 +248,6 @@ template <typename T>
 | 
				
			|||||||
void Affine2D<T>::RotateScaleYTo(const v2T& v)
 | 
					void Affine2D<T>::RotateScaleYTo(const v2T& v)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Affine2D<T> rs = CalcRotateScale(Y(), v);
 | 
						Affine2D<T> rs = CalcRotateScale(Y(), v);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	X(rs.TransformNormal(X()));
 | 
						X(rs.TransformNormal(X()));
 | 
				
			||||||
	Y(rs.TransformNormal(Y()));
 | 
						Y(rs.TransformNormal(Y()));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -232,7 +260,6 @@ template <typename T>
 | 
				
			|||||||
Affine2D<T> Affine2D<T>::Inverse() const
 | 
					Affine2D<T> Affine2D<T>::Inverse() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	T det = A() * E() - D() * B();
 | 
						T det = A() * E() - D() * B();
 | 
				
			||||||
 | 
					 | 
				
			||||||
	return Affine2D<T>(E() / det, -D() / det,
 | 
						return Affine2D<T>(E() / det, -D() / det,
 | 
				
			||||||
					   -B() / det,  A() / det,
 | 
										   -B() / det,  A() / det,
 | 
				
			||||||
					   (F() * B() - C() * E()) / det, (C() * D() - F() * A()) / det);
 | 
										   (F() * B() - C() * E()) / det, (C() * D() - F() * A()) / det);
 | 
				
			||||||
@ -296,7 +323,6 @@ typename m4T Affine2D<T>::ToMat4ColMajor(bool center) const
 | 
				
			|||||||
			D(), E(), 0, center ? 0 : F(), //1
 | 
								D(), E(), 0, center ? 0 : F(), //1
 | 
				
			||||||
			0,   0, 1,			    0, //2
 | 
								0,   0, 1,			    0, //2
 | 
				
			||||||
			0,   0, 0,			    1);//3
 | 
								0,   0, 0,			    1);//3
 | 
				
			||||||
 | 
					 | 
				
			||||||
	return mat;
 | 
						return mat;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -312,7 +338,6 @@ typename m4T Affine2D<T>::ToMat4RowMajor(bool center) const
 | 
				
			|||||||
			B(), E(), 0, 0,
 | 
								B(), E(), 0, 0,
 | 
				
			||||||
			0,   0, 1, 0,
 | 
								0,   0, 1, 0,
 | 
				
			||||||
			center ? 0 : C(), center ? 0 : F(), 0, 1);
 | 
								center ? 0 : C(), center ? 0 : F(), 0, 1);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	return mat;
 | 
						return mat;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -351,7 +376,6 @@ template <typename T>
 | 
				
			|||||||
Affine2D<T> Affine2D<T>::CalcRotateScale(const v2T& from, const v2T& to)
 | 
					Affine2D<T> Affine2D<T>::CalcRotateScale(const v2T& from, const v2T& to)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	T a, c;
 | 
						T a, c;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	CalcRSAC(from, to, a, c);
 | 
						CalcRSAC(from, to, a, c);
 | 
				
			||||||
	return Affine2D<T>(a, c, -c, a, 0, 0);
 | 
						return Affine2D<T>(a, c, -c, a, 0, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -368,7 +392,6 @@ template <typename T>
 | 
				
			|||||||
void Affine2D<T>::CalcRSAC(const v2T& from, const v2T& to, T& a, T& c)
 | 
					void Affine2D<T>::CalcRSAC(const v2T& from, const v2T& to, T& a, T& c)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	T lsq = from.x * from.x + from.y * from.y;
 | 
						T lsq = from.x * from.x + from.y * from.y;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	a = (from.y * to.y + from.x * to.x) / lsq;
 | 
						a = (from.y * to.y + from.x * to.x) / lsq;
 | 
				
			||||||
	c = (from.x * to.y - from.y * to.x) / lsq;
 | 
						c = (from.x * to.y - from.y * to.x) / lsq;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -64,17 +64,19 @@ public:
 | 
				
			|||||||
		D(T(affine.D()));
 | 
							D(T(affine.D()));
 | 
				
			||||||
		E(T(affine.E()));
 | 
							E(T(affine.E()));
 | 
				
			||||||
		F(T(affine.F()));
 | 
							F(T(affine.F()));
 | 
				
			||||||
 | 
					 | 
				
			||||||
		return *this;
 | 
							return *this;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool operator == (const Affine2D<T>& affine);
 | 
						bool operator == (const Affine2D<T>& affine);
 | 
				
			||||||
	v2T operator * (const v2T& v);
 | 
						v2T operator * (const v2T& v);
 | 
				
			||||||
 | 
						Affine2D<T> operator * (const T& t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void MakeID();
 | 
						void MakeID();
 | 
				
			||||||
	bool IsID() const;
 | 
						bool IsID() const;
 | 
				
			||||||
	bool IsZero() const;
 | 
						bool IsZero() const;
 | 
				
			||||||
	bool IsEmpty() const;
 | 
						bool IsEmpty() const;
 | 
				
			||||||
 | 
						void Scale(T amount);
 | 
				
			||||||
 | 
						Affine2D<T> ScaleCopy(T amount);
 | 
				
			||||||
	void Rotate(T angle);
 | 
						void Rotate(T angle);
 | 
				
			||||||
	void Translate(const v2T& v);
 | 
						void Translate(const v2T& v);
 | 
				
			||||||
	void RotateScaleXTo(const v2T& v);
 | 
						void RotateScaleXTo(const v2T& v);
 | 
				
			||||||
 | 
				
			|||||||
@ -314,8 +314,6 @@ public:
 | 
				
			|||||||
	/// <returns>True if success, else false.</returns>
 | 
						/// <returns>True if success, else false.</returns>
 | 
				
			||||||
	bool DeleteXform(size_t i)
 | 
						bool DeleteXform(size_t i)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Xform<T>* xform;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (i < XformCount())
 | 
							if (i < XformCount())
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			m_Xforms.erase(m_Xforms.begin() + i);
 | 
								m_Xforms.erase(m_Xforms.begin() + i);
 | 
				
			||||||
@ -323,7 +321,7 @@ public:
 | 
				
			|||||||
			//Now shuffle xaos values from i on back by 1 for every xform.
 | 
								//Now shuffle xaos values from i on back by 1 for every xform.
 | 
				
			||||||
			for (size_t x1 = 0; x1 < XformCount(); x1++)
 | 
								for (size_t x1 = 0; x1 < XformCount(); x1++)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				if ((xform = GetXform(x1)))
 | 
									if (auto xform = GetXform(x1))
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					for (size_t x2 = i + 1; x2 <= XformCount(); x2++)//Iterate from the position after the deletion index up to the old count.
 | 
										for (size_t x2 = i + 1; x2 <= XformCount(); x2++)//Iterate from the position after the deletion index up to the old count.
 | 
				
			||||||
						xform->SetXaos(x2 - 1, xform->Xaos(x2));
 | 
											xform->SetXaos(x2 - 1, xform->Xaos(x2));
 | 
				
			||||||
@ -463,7 +461,7 @@ public:
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		for (size_t i = 0; i < TotalXformCount(); i++)
 | 
							for (size_t i = 0; i < TotalXformCount(); i++)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			Xform<T>* xform = GetTotalXform(i);
 | 
								auto xform = GetTotalXform(i);
 | 
				
			||||||
			xform->CacheColorVals();
 | 
								xform->CacheColorVals();
 | 
				
			||||||
			xform->SetPrecalcFlags();
 | 
								xform->SetPrecalcFlags();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -824,7 +822,7 @@ public:
 | 
				
			|||||||
		//This includes all xforms plus final.
 | 
							//This includes all xforms plus final.
 | 
				
			||||||
		for (size_t i = 0; i < totalXformCount; i++)
 | 
							for (size_t i = 0; i < totalXformCount; i++)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			Xform<T>* thisXform = GetTotalXform(i);
 | 
								auto thisXform = GetTotalXform(i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (size == 2 && stagger > 0 && thisXform != &m_FinalXform)
 | 
								if (size == 2 && stagger > 0 && thisXform != &m_FinalXform)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
@ -845,7 +843,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
				for (size_t k = 0; k < size; k++)//For each ember in the list.
 | 
									for (size_t k = 0; k < size; k++)//For each ember in the list.
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Xform<T>* tempXform = embers[k].GetTotalXform(i);//Xform in this position in this ember, including final.
 | 
										auto tempXform = embers[k].GetTotalXform(i);//Xform in this position in this ember, including final.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					if (tempXform)
 | 
										if (tempXform)
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
@ -904,7 +902,7 @@ public:
 | 
				
			|||||||
				{
 | 
									{
 | 
				
			||||||
					if (i < embers[k].TotalXformCount())//Xform in this position in this ember.
 | 
										if (i < embers[k].TotalXformCount())//Xform in this position in this ember.
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
						Xform<T>* tempXform = embers[k].GetTotalXform(i);
 | 
											auto tempXform = embers[k].GetTotalXform(i);
 | 
				
			||||||
						allID &= tempXform->m_Post.IsID();
 | 
											allID &= tempXform->m_Post.IsID();
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@ -931,7 +929,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
				for (size_t k = 0; k < size; k++)
 | 
									for (size_t k = 0; k < size; k++)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Xform<T>* tempXform = embers[k].GetTotalXform(i);//Xform in this position in this ember.
 | 
										auto tempXform = embers[k].GetTotalXform(i);//Xform in this position in this ember.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					if (tempXform)
 | 
										if (tempXform)
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
@ -971,7 +969,7 @@ public:
 | 
				
			|||||||
				//Now fill them with interpolated values.
 | 
									//Now fill them with interpolated values.
 | 
				
			||||||
				for (size_t j = 0; j < size; j++)//For each ember in the list.
 | 
									for (size_t j = 0; j < size; j++)//For each ember in the list.
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Xform<T>* tempXform = embers[j].GetXform(i);
 | 
										auto tempXform = embers[j].GetXform(i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					for (size_t k = 0; k < XformCount(); k++)//For each xaos entry in this xform's xaos array, sum it with the same entry in all of the embers multiplied by the coef for that ember.
 | 
										for (size_t k = 0; k < XformCount(); k++)//For each xaos entry in this xform's xaos array, sum it with the same entry in all of the embers multiplied by the coef for that ember.
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
 | 
				
			|||||||
@ -41,7 +41,6 @@ public:
 | 
				
			|||||||
		bool aligned = true;
 | 
							bool aligned = true;
 | 
				
			||||||
		bool currentFinal, final = sourceEmbers[0].UseFinalXform();
 | 
							bool currentFinal, final = sourceEmbers[0].UseFinalXform();
 | 
				
			||||||
		size_t i, xf, currentCount, maxCount = sourceEmbers[0].XformCount();
 | 
							size_t i, xf, currentCount, maxCount = sourceEmbers[0].XformCount();
 | 
				
			||||||
		Xform<T>* destXform;
 | 
					 | 
				
			||||||
		Xform<T>* destOtherXform;
 | 
							Xform<T>* destOtherXform;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		//Determine the max number of xforms present in sourceEmbers.
 | 
							//Determine the max number of xforms present in sourceEmbers.
 | 
				
			||||||
@ -84,7 +83,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			for (xf = 0; xf < maxCount; xf++)//This will include both normal xforms and the final.
 | 
								for (xf = 0; xf < maxCount; xf++)//This will include both normal xforms and the final.
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				destXform = destEmbers[i].GetTotalXform(xf, final);
 | 
									auto destXform = destEmbers[i].GetTotalXform(xf, final);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				//Ensure every parametric variation contained in every xform at either position i - 1 or i + 1 is also contained in the dest xform.
 | 
									//Ensure every parametric variation contained in every xform at either position i - 1 or i + 1 is also contained in the dest xform.
 | 
				
			||||||
				if (i > 0)
 | 
									if (i > 0)
 | 
				
			||||||
@ -607,7 +606,7 @@ public:
 | 
				
			|||||||
				//Keep translation linear.
 | 
									//Keep translation linear.
 | 
				
			||||||
				zlm[0] = zlm[1] = 0;
 | 
									zlm[0] = zlm[1] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (Xform<T>* xform = embers[k].GetTotalXform(xfi))
 | 
									if (auto xform = embers[k].GetTotalXform(xfi))
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					for (col = 0; col < 2; col++)
 | 
										for (col = 0; col < 2; col++)
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
@ -650,7 +649,7 @@ public:
 | 
				
			|||||||
			{
 | 
								{
 | 
				
			||||||
				for (k = 1; k < size; k++)
 | 
									for (k = 1; k < size; k++)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					if (Xform<T>* xform = embers[k].GetTotalXform(xfi))
 | 
										if (auto xform = embers[k].GetTotalXform(xfi))
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
						//Adjust angles differently if an asymmetric case.
 | 
											//Adjust angles differently if an asymmetric case.
 | 
				
			||||||
						if (xform->m_Wind[col] > 0 && cflag == 0)
 | 
											if (xform->m_Wind[col] > 0 && cflag == 0)
 | 
				
			||||||
 | 
				
			|||||||
@ -98,7 +98,7 @@ public:
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		size_t i;
 | 
							size_t i;
 | 
				
			||||||
		size_t distribCount = ember.XaosPresent() ? ember.XformCount() + 1 : 1;
 | 
							size_t distribCount = ember.XaosPresent() ? ember.XformCount() + 1 : 1;
 | 
				
			||||||
		const Xform<T>* xforms = ember.Xforms();
 | 
							auto xforms = ember.Xforms();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (m_XformDistributions.size() < CHOOSE_XFORM_GRAIN * distribCount)
 | 
							if (m_XformDistributions.size() < CHOOSE_XFORM_GRAIN * distribCount)
 | 
				
			||||||
			m_XformDistributions.resize(CHOOSE_XFORM_GRAIN * distribCount);
 | 
								m_XformDistributions.resize(CHOOSE_XFORM_GRAIN * distribCount);
 | 
				
			||||||
@ -306,7 +306,7 @@ public:
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		size_t i, badVals = 0;
 | 
							size_t i, badVals = 0;
 | 
				
			||||||
		Point<T> tempPoint, p1;
 | 
							Point<T> tempPoint, p1;
 | 
				
			||||||
		Xform<T>* xforms = ember.NonConstXforms();
 | 
							auto xforms = ember.NonConstXforms();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (ember.ProjBits())
 | 
							if (ember.ProjBits())
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@ -473,7 +473,7 @@ public:
 | 
				
			|||||||
		size_t lastXformUsed = 0;
 | 
							size_t lastXformUsed = 0;
 | 
				
			||||||
		size_t badVals = 0;
 | 
							size_t badVals = 0;
 | 
				
			||||||
		Point<T> tempPoint, p1;
 | 
							Point<T> tempPoint, p1;
 | 
				
			||||||
		Xform<T>* xforms = ember.NonConstXforms();
 | 
							auto xforms = ember.NonConstXforms();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (ember.ProjBits())
 | 
							if (ember.ProjBits())
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
 | 
				
			|||||||
@ -118,7 +118,7 @@ public:
 | 
				
			|||||||
		//First clear out any xforms that are not the final, and have a density of less than 0.001.
 | 
							//First clear out any xforms that are not the final, and have a density of less than 0.001.
 | 
				
			||||||
		for (i = 0; i < ember.XformCount(); i++)
 | 
							for (i = 0; i < ember.XformCount(); i++)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			Xform<T>* xform = ember.GetXform(i);
 | 
								auto xform = ember.GetXform(i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (xform->m_Weight < T(0.001))
 | 
								if (xform->m_Weight < T(0.001))
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
@ -131,7 +131,7 @@ public:
 | 
				
			|||||||
		//Now consider all xforms, including final.
 | 
							//Now consider all xforms, including final.
 | 
				
			||||||
		for (i = 0; i < ember.TotalXformCount(); i++)
 | 
							for (i = 0; i < ember.TotalXformCount(); i++)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			Xform<T>* xform = ember.GetTotalXform(i);
 | 
								auto xform = ember.GetTotalXform(i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			do
 | 
								do
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
@ -223,8 +223,8 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
				for (size_t i = 0; i < ember.TotalXformCount(); i++)
 | 
									for (size_t i = 0; i < ember.TotalXformCount(); i++)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Xform<T>* xform1 = ember.GetTotalXform(i);
 | 
										auto xform1 = ember.GetTotalXform(i);
 | 
				
			||||||
					Xform<T>* xform2 = mutation.GetTotalXform(i);
 | 
										auto xform2 = mutation.GetTotalXform(i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					if (xform1 && xform2)
 | 
										if (xform1 && xform2)
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
@ -254,8 +254,8 @@ public:
 | 
				
			|||||||
			Random(mutation, useVars, sym, 2, maxVars);
 | 
								Random(mutation, useVars, sym, 2, maxVars);
 | 
				
			||||||
			//Which xform to mutate?
 | 
								//Which xform to mutate?
 | 
				
			||||||
			modXform = m_Rand.Rand() % ember.TotalXformCount();
 | 
								modXform = m_Rand.Rand() % ember.TotalXformCount();
 | 
				
			||||||
			Xform<T>* xform1 = ember.GetTotalXform(modXform);
 | 
								auto xform1 = ember.GetTotalXform(modXform);
 | 
				
			||||||
			Xform<T>* xform2 = mutation.GetTotalXform(0);
 | 
								auto xform2 = mutation.GetTotalXform(0);
 | 
				
			||||||
			os << "mutate xform " << modXform << " coefs";
 | 
								os << "mutate xform " << modXform << " coefs";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			//If less than 3 xforms, then change only the translation part.
 | 
								//If less than 3 xforms, then change only the translation part.
 | 
				
			||||||
@ -285,7 +285,7 @@ public:
 | 
				
			|||||||
			for (size_t i = 0; i < ember.TotalXformCount(); i++)
 | 
								for (size_t i = 0; i < ember.TotalXformCount(); i++)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				bool copy = (i > 0) && same;
 | 
									bool copy = (i > 0) && same;
 | 
				
			||||||
				Xform<T>* xform = ember.GetTotalXform(i);
 | 
									auto xform = ember.GetTotalXform(i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (copy)//Copy the post from the first xform to the rest of them.
 | 
									if (copy)//Copy the post from the first xform to the rest of them.
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
@ -400,8 +400,8 @@ public:
 | 
				
			|||||||
			//Change all the coefs by a fraction of the random.
 | 
								//Change all the coefs by a fraction of the random.
 | 
				
			||||||
			for (size_t x = 0; x < ember.TotalXformCount(); x++)
 | 
								for (size_t x = 0; x < ember.TotalXformCount(); x++)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				Xform<T>* xform1 = ember.GetTotalXform(x);
 | 
									auto xform1 = ember.GetTotalXform(x);
 | 
				
			||||||
				Xform<T>* xform2 = mutation.GetTotalXform(x);
 | 
									auto xform2 = mutation.GetTotalXform(x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				for (glm::length_t i = 0; i < 2; i++)
 | 
									for (glm::length_t i = 0; i < 2; i++)
 | 
				
			||||||
					for (glm::length_t j = 0; j < 3; j++)
 | 
										for (glm::length_t j = 0; j < 3; j++)
 | 
				
			||||||
@ -498,7 +498,7 @@ public:
 | 
				
			|||||||
						{
 | 
											{
 | 
				
			||||||
							if (i < ember1.XformCount() && ember1.GetXform(i)->m_Weight > 0)
 | 
												if (i < ember1.XformCount() && ember1.GetXform(i)->m_Weight > 0)
 | 
				
			||||||
							{
 | 
												{
 | 
				
			||||||
								Xform<T>* xform = emberOut.GetXform(i);
 | 
													auto xform = emberOut.GetXform(i);
 | 
				
			||||||
								*xform = *ember1.GetXform(i);
 | 
													*xform = *ember1.GetXform(i);
 | 
				
			||||||
								os << " 1";
 | 
													os << " 1";
 | 
				
			||||||
								got1 = 1;
 | 
													got1 = 1;
 | 
				
			||||||
@ -513,7 +513,7 @@ public:
 | 
				
			|||||||
						{
 | 
											{
 | 
				
			||||||
							if (i < ember0.XformCount() && ember0.GetXform(i)->m_Weight > 0)
 | 
												if (i < ember0.XformCount() && ember0.GetXform(i)->m_Weight > 0)
 | 
				
			||||||
							{
 | 
												{
 | 
				
			||||||
								Xform<T>* xform = emberOut.GetXform(i);
 | 
													auto xform = emberOut.GetXform(i);
 | 
				
			||||||
								*xform = *ember0.GetXform(i);
 | 
													*xform = *ember0.GetXform(i);
 | 
				
			||||||
								os << " 0";
 | 
													os << " 0";
 | 
				
			||||||
								got0 = 1;
 | 
													got0 = 1;
 | 
				
			||||||
@ -654,7 +654,7 @@ public:
 | 
				
			|||||||
		//Loop over xforms.
 | 
							//Loop over xforms.
 | 
				
			||||||
		for (i = 0; i < ember.TotalXformCount(); i++)
 | 
							for (i = 0; i < ember.TotalXformCount(); i++)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			Xform<T>* xform = ember.GetTotalXform(i);
 | 
								auto xform = ember.GetTotalXform(i);
 | 
				
			||||||
			xform->m_Weight = T(1) / ember.TotalXformCount();
 | 
								xform->m_Weight = T(1) / ember.TotalXformCount();
 | 
				
			||||||
			xform->m_ColorX = m_Rand.Frand01<T>();//Original pingponged between 0 and 1, which gives bad coloring. Ember does random instead.
 | 
								xform->m_ColorX = m_Rand.Frand01<T>();//Original pingponged between 0 and 1, which gives bad coloring. Ember does random instead.
 | 
				
			||||||
			xform->m_ColorY = m_Rand.Frand01<T>();//Will need to update this if 2D coordinates are ever supported.
 | 
								xform->m_ColorY = m_Rand.Frand01<T>();//Will need to update this if 2D coordinates are ever supported.
 | 
				
			||||||
@ -699,7 +699,7 @@ public:
 | 
				
			|||||||
					if (samed && i > 0)
 | 
										if (samed && i > 0)
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
						//Copy the same variations from the previous xform.
 | 
											//Copy the same variations from the previous xform.
 | 
				
			||||||
						Xform<T>* prevXform = ember.GetXform(i - 1);
 | 
											auto prevXform = ember.GetXform(i - 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						for (j = 0; j < prevXform->TotalVariationCount(); j++)
 | 
											for (j = 0; j < prevXform->TotalVariationCount(); j++)
 | 
				
			||||||
							if (xform->TotalVariationCount() < maxVars)
 | 
												if (xform->TotalVariationCount() < maxVars)
 | 
				
			||||||
@ -893,10 +893,6 @@ public:
 | 
				
			|||||||
	/// <param name="changePalette">Change palette if true, else don't</param>
 | 
						/// <param name="changePalette">Change palette if true, else don't</param>
 | 
				
			||||||
	void ChangeColors(Ember<T>& ember, bool changePalette)
 | 
						void ChangeColors(Ember<T>& ember, bool changePalette)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		size_t i;
 | 
					 | 
				
			||||||
		Xform<T>* xform0;
 | 
					 | 
				
			||||||
		Xform<T>* xform1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (changePalette)
 | 
							if (changePalette)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (m_PaletteList.Size())
 | 
								if (m_PaletteList.Size())
 | 
				
			||||||
@ -910,14 +906,14 @@ public:
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (i = 0; i < ember.TotalXformCount(); i++)
 | 
							for (size_t i = 0; i < ember.TotalXformCount(); i++)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			ember.GetTotalXform(i)->m_ColorX = m_Rand.Frand01<T>();
 | 
								ember.GetTotalXform(i)->m_ColorX = m_Rand.Frand01<T>();
 | 
				
			||||||
			ember.GetTotalXform(i)->m_ColorY = m_Rand.Frand01<T>();
 | 
								ember.GetTotalXform(i)->m_ColorY = m_Rand.Frand01<T>();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		xform0 = RandomXform(ember, -1);
 | 
							auto xform0 = RandomXform(ember, -1);
 | 
				
			||||||
		xform1 = RandomXform(ember, ember.GetXformIndex(xform0));
 | 
							auto xform1 = RandomXform(ember, ember.GetXformIndex(xform0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (xform0 && (m_Rand.Rand() & 1))
 | 
							if (xform0 && (m_Rand.Rand() & 1))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@ -949,7 +945,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			if (i != excluded)
 | 
								if (i != excluded)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				Xform<T>* xform = ember.GetTotalXform(i);
 | 
									auto xform = ember.GetTotalXform(i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (xform->m_Weight > 0)
 | 
									if (xform->m_Weight > 0)
 | 
				
			||||||
					return xform;
 | 
										return xform;
 | 
				
			||||||
@ -975,8 +971,8 @@ public:
 | 
				
			|||||||
		//the result xforms before rotate is called.
 | 
							//the result xforms before rotate is called.
 | 
				
			||||||
		for (size_t i = 0; i < ember.TotalXformCount(); i++)
 | 
							for (size_t i = 0; i < ember.TotalXformCount(); i++)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			Xform<T>* xform1 = ember.GetTotalXform(i);
 | 
								auto xform1 = ember.GetTotalXform(i);
 | 
				
			||||||
			Xform<T>* xform2 = rotated.GetTotalXform(i);
 | 
								auto xform2 = rotated.GetTotalXform(i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!xform1->m_Motion.empty())
 | 
								if (!xform1->m_Motion.empty())
 | 
				
			||||||
				xform2->ApplyMotion(*xform1, blend);
 | 
									xform2->ApplyMotion(*xform1, blend);
 | 
				
			||||||
@ -1009,7 +1005,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			for (i = 0; i < embers[si].TotalXformCount(); i++)
 | 
								for (i = 0; i < embers[si].TotalXformCount(); i++)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				Xform<T>* xform = embers[si].GetTotalXform(i);
 | 
									auto xform = embers[si].GetTotalXform(i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (!xform->m_Motion.empty())
 | 
									if (!xform->m_Motion.empty())
 | 
				
			||||||
					xform->ApplyMotion(*(prealign[si].GetTotalXform(i)), blend);//Apply motion parameters to result.xform[i] using blend parameter.
 | 
										xform->ApplyMotion(*(prealign[si].GetTotalXform(i)), blend);//Apply motion parameters to result.xform[i] using blend parameter.
 | 
				
			||||||
 | 
				
			|||||||
@ -54,7 +54,7 @@ string IterOpenCLKernelCreator<T>::CreateIterKernelString(const Ember<T>& ember,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < totalXformCount; i++)
 | 
						for (i = 0; i < totalXformCount; i++)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Xform<T>* xform = ember.GetTotalXform(i);
 | 
							auto xform = ember.GetTotalXform(i);
 | 
				
			||||||
		bool needPrecalcSumSquares = false;
 | 
							bool needPrecalcSumSquares = false;
 | 
				
			||||||
		bool needPrecalcSqrtSumSquares = false;
 | 
							bool needPrecalcSqrtSumSquares = false;
 | 
				
			||||||
		bool needPrecalcAngles = false;
 | 
							bool needPrecalcAngles = false;
 | 
				
			||||||
@ -831,9 +831,9 @@ bool IterOpenCLKernelCreator<T>::IsBuildRequired(const Ember<T>& ember1, const E
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < xformCount; i++)
 | 
						for (i = 0; i < xformCount; i++)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Xform<T>* xform1 = ember1.GetTotalXform(i);
 | 
							auto xform1 = ember1.GetTotalXform(i);
 | 
				
			||||||
		Xform<T>* xform2 = ember2.GetTotalXform(i);
 | 
							auto xform2 = ember2.GetTotalXform(i);
 | 
				
			||||||
		size_t varCount = xform1->TotalVariationCount();
 | 
							auto varCount = xform1->TotalVariationCount();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (xform1->HasPost() != xform2->HasPost())
 | 
							if (xform1->HasPost() != xform2->HasPost())
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
 | 
				
			|||||||
@ -1750,7 +1750,7 @@ void RendererCL<T, bucketT>::ConvertEmber(Ember<T>& ember, EmberCL<T>& emberCL,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for (size_t i = 0; i < ember.TotalXformCount() && i < xformsCL.size(); i++)
 | 
						for (size_t i = 0; i < ember.TotalXformCount() && i < xformsCL.size(); i++)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Xform<T>* xform = ember.GetTotalXform(i);
 | 
							auto xform = ember.GetTotalXform(i);
 | 
				
			||||||
		xformsCL[i].m_A = xform->m_Affine.A();
 | 
							xformsCL[i].m_A = xform->m_Affine.A();
 | 
				
			||||||
		xformsCL[i].m_B = xform->m_Affine.B();
 | 
							xformsCL[i].m_B = xform->m_Affine.B();
 | 
				
			||||||
		xformsCL[i].m_C = xform->m_Affine.C();
 | 
							xformsCL[i].m_C = xform->m_Affine.C();
 | 
				
			||||||
 | 
				
			|||||||
@ -1880,7 +1880,6 @@ void DistribTester()
 | 
				
			|||||||
	size_t distribCount = 1;
 | 
						size_t distribCount = 1;
 | 
				
			||||||
	size_t xformCount = 3;
 | 
						size_t xformCount = 3;
 | 
				
			||||||
	vector<byte> m_XformDistributions;
 | 
						vector<byte> m_XformDistributions;
 | 
				
			||||||
	//const Xform<T>* xforms = 3;
 | 
					 | 
				
			||||||
	size_t j = 0;
 | 
						size_t j = 0;
 | 
				
			||||||
	vector<T> weights { T(0.333333), T(1.0), T(0.25) };
 | 
						vector<T> weights { T(0.333333), T(1.0), T(0.25) };
 | 
				
			||||||
	double tempDensity = 0, currentDensityLimit = 0, densityPerElement;
 | 
						double tempDensity = 0, currentDensityLimit = 0, densityPerElement;
 | 
				
			||||||
 | 
				
			|||||||
@ -247,7 +247,7 @@ void FractoriumEmberController<T>::ApplyXmlSavingTemplate(Ember<T>& ember)
 | 
				
			|||||||
/// <returns>True if the current ember contains a final xform, else false.</returns>
 | 
					/// <returns>True if the current ember contains a final xform, else false.</returns>
 | 
				
			||||||
bool Fractorium::HaveFinal()
 | 
					bool Fractorium::HaveFinal()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	QComboBox* combo = ui.CurrentXformCombo;
 | 
						auto combo = ui.CurrentXformCombo;
 | 
				
			||||||
	return (combo->count() > 0 && combo->itemText(combo->count() - 1) == "Final");
 | 
						return (combo->count() > 0 && combo->itemText(combo->count() - 1) == "Final");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -389,7 +389,9 @@ void Fractorium::dragEnterEvent(QDragEnterEvent* e)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	if (e->mimeData()->hasUrls())
 | 
						if (e->mimeData()->hasUrls())
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		foreach (QUrl url, e->mimeData()->urls())
 | 
							auto urls = e->mimeData()->urls();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto& url : urls)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			QString localFile = url.toLocalFile();
 | 
								QString localFile = url.toLocalFile();
 | 
				
			||||||
			QFileInfo fileInfo(localFile);
 | 
								QFileInfo fileInfo(localFile);
 | 
				
			||||||
@ -426,7 +428,9 @@ void Fractorium::dropEvent(QDropEvent* e)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (e->mimeData()->hasUrls())
 | 
						if (e->mimeData()->hasUrls())
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		foreach (QUrl url, e->mimeData()->urls())
 | 
							auto urls = e->mimeData()->urls();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto& url : urls)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			QString localFile = url.toLocalFile();
 | 
								QString localFile = url.toLocalFile();
 | 
				
			||||||
			QFileInfo fileInfo(localFile);
 | 
								QFileInfo fileInfo(localFile);
 | 
				
			||||||
 | 
				
			|||||||
@ -203,8 +203,10 @@ public slots:
 | 
				
			|||||||
	void OnXformWeightChanged(double d);
 | 
						void OnXformWeightChanged(double d);
 | 
				
			||||||
	void OnEqualWeightButtonClicked(bool checked);
 | 
						void OnEqualWeightButtonClicked(bool checked);
 | 
				
			||||||
	void OnXformNameChanged(int row, int col);
 | 
						void OnXformNameChanged(int row, int col);
 | 
				
			||||||
 | 
						void OnXformAnimateCheckBoxStateChanged(int state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//Xforms Affine.
 | 
						//Xforms Affine.
 | 
				
			||||||
 | 
						void OnLockAffineScaleCheckBoxStateChanged(int state);
 | 
				
			||||||
	void OnPreAffineRowDoubleClicked(int logicalIndex);
 | 
						void OnPreAffineRowDoubleClicked(int logicalIndex);
 | 
				
			||||||
	void OnPreAffineColDoubleClicked(int logicalIndex);
 | 
						void OnPreAffineColDoubleClicked(int logicalIndex);
 | 
				
			||||||
	void OnPostAffineRowDoubleClicked(int logicalIndex);
 | 
						void OnPostAffineRowDoubleClicked(int logicalIndex);
 | 
				
			||||||
 | 
				
			|||||||
@ -2350,7 +2350,7 @@
 | 
				
			|||||||
     <property name="minimumSize">
 | 
					     <property name="minimumSize">
 | 
				
			||||||
      <size>
 | 
					      <size>
 | 
				
			||||||
       <width>291</width>
 | 
					       <width>291</width>
 | 
				
			||||||
       <height>613</height>
 | 
					       <height>632</height>
 | 
				
			||||||
      </size>
 | 
					      </size>
 | 
				
			||||||
     </property>
 | 
					     </property>
 | 
				
			||||||
     <property name="features">
 | 
					     <property name="features">
 | 
				
			||||||
@ -2756,7 +2756,7 @@
 | 
				
			|||||||
         </item>
 | 
					         </item>
 | 
				
			||||||
        </widget>
 | 
					        </widget>
 | 
				
			||||||
       </item>
 | 
					       </item>
 | 
				
			||||||
       <item row="2" column="0">
 | 
					       <item row="3" column="0">
 | 
				
			||||||
        <widget class="QTabWidget" name="XformsTabWidget">
 | 
					        <widget class="QTabWidget" name="XformsTabWidget">
 | 
				
			||||||
         <property name="sizePolicy">
 | 
					         <property name="sizePolicy">
 | 
				
			||||||
          <sizepolicy hsizetype="Ignored" vsizetype="MinimumExpanding">
 | 
					          <sizepolicy hsizetype="Ignored" vsizetype="MinimumExpanding">
 | 
				
			||||||
@ -2780,7 +2780,7 @@
 | 
				
			|||||||
          <enum>QTabWidget::Triangular</enum>
 | 
					          <enum>QTabWidget::Triangular</enum>
 | 
				
			||||||
         </property>
 | 
					         </property>
 | 
				
			||||||
         <property name="currentIndex">
 | 
					         <property name="currentIndex">
 | 
				
			||||||
          <number>2</number>
 | 
					          <number>1</number>
 | 
				
			||||||
         </property>
 | 
					         </property>
 | 
				
			||||||
         <widget class="QWidget" name="XformColorTab">
 | 
					         <widget class="QWidget" name="XformColorTab">
 | 
				
			||||||
          <property name="sizePolicy">
 | 
					          <property name="sizePolicy">
 | 
				
			||||||
@ -3444,6 +3444,13 @@
 | 
				
			|||||||
           <property name="bottomMargin">
 | 
					           <property name="bottomMargin">
 | 
				
			||||||
            <number>5</number>
 | 
					            <number>5</number>
 | 
				
			||||||
           </property>
 | 
					           </property>
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <widget class="QCheckBox" name="LockAffineCheckBox">
 | 
				
			||||||
 | 
					             <property name="text">
 | 
				
			||||||
 | 
					              <string>Lock Affine Scale</string>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					            </widget>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
           <item>
 | 
					           <item>
 | 
				
			||||||
            <widget class="QScrollArea" name="AffineTabScrollArea">
 | 
					            <widget class="QScrollArea" name="AffineTabScrollArea">
 | 
				
			||||||
             <property name="autoFillBackground">
 | 
					             <property name="autoFillBackground">
 | 
				
			||||||
@ -3464,7 +3471,7 @@
 | 
				
			|||||||
                <x>0</x>
 | 
					                <x>0</x>
 | 
				
			||||||
                <y>0</y>
 | 
					                <y>0</y>
 | 
				
			||||||
                <width>263</width>
 | 
					                <width>263</width>
 | 
				
			||||||
                <height>743</height>
 | 
					                <height>700</height>
 | 
				
			||||||
               </rect>
 | 
					               </rect>
 | 
				
			||||||
              </property>
 | 
					              </property>
 | 
				
			||||||
              <property name="autoFillBackground">
 | 
					              <property name="autoFillBackground">
 | 
				
			||||||
@ -5479,7 +5486,7 @@
 | 
				
			|||||||
                   <x>0</x>
 | 
					                   <x>0</x>
 | 
				
			||||||
                   <y>0</y>
 | 
					                   <y>0</y>
 | 
				
			||||||
                   <width>259</width>
 | 
					                   <width>259</width>
 | 
				
			||||||
                   <height>673</height>
 | 
					                   <height>652</height>
 | 
				
			||||||
                  </rect>
 | 
					                  </rect>
 | 
				
			||||||
                 </property>
 | 
					                 </property>
 | 
				
			||||||
                 <property name="sizePolicy">
 | 
					                 <property name="sizePolicy">
 | 
				
			||||||
@ -5529,6 +5536,16 @@
 | 
				
			|||||||
         </widget>
 | 
					         </widget>
 | 
				
			||||||
        </widget>
 | 
					        </widget>
 | 
				
			||||||
       </item>
 | 
					       </item>
 | 
				
			||||||
 | 
					       <item row="2" column="0">
 | 
				
			||||||
 | 
					        <widget class="QCheckBox" name="AnimateXformCheckBox">
 | 
				
			||||||
 | 
					         <property name="toolTip">
 | 
				
			||||||
 | 
					          <string><html><head/><body><p>Rotate this xform when creating a sequence for animation</p></body></html></string>
 | 
				
			||||||
 | 
					         </property>
 | 
				
			||||||
 | 
					         <property name="text">
 | 
				
			||||||
 | 
					          <string>Animate</string>
 | 
				
			||||||
 | 
					         </property>
 | 
				
			||||||
 | 
					        </widget>
 | 
				
			||||||
 | 
					       </item>
 | 
				
			||||||
      </layout>
 | 
					      </layout>
 | 
				
			||||||
     </widget>
 | 
					     </widget>
 | 
				
			||||||
    </widget>
 | 
					    </widget>
 | 
				
			||||||
 | 
				
			|||||||
@ -15,6 +15,7 @@ FractoriumEmberControllerBase::FractoriumEmberControllerBase(Fractorium* fractor
 | 
				
			|||||||
	m_Shared = true;
 | 
						m_Shared = true;
 | 
				
			||||||
	m_FailedRenders = 0;
 | 
						m_FailedRenders = 0;
 | 
				
			||||||
	m_UndoIndex = 0;
 | 
						m_UndoIndex = 0;
 | 
				
			||||||
 | 
						m_LockedScale = 1;
 | 
				
			||||||
	m_RenderType = eRendererType::CPU_RENDERER;
 | 
						m_RenderType = eRendererType::CPU_RENDERER;
 | 
				
			||||||
	m_OutputTexID = 0;
 | 
						m_OutputTexID = 0;
 | 
				
			||||||
	m_SubBatchCount = 1;//Will be ovewritten by the options on first render.
 | 
						m_SubBatchCount = 1;//Will be ovewritten by the options on first render.
 | 
				
			||||||
@ -224,6 +225,7 @@ void FractoriumEmberController<T>::Update(std::function<void (void)> func, bool
 | 
				
			|||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
/// Wrapper to call a function on the specified xforms, then optionally add the requested action to the rendering queue.
 | 
					/// Wrapper to call a function on the specified xforms, then optionally add the requested action to the rendering queue.
 | 
				
			||||||
/// If no xforms are selected via the checkboxes, and the update type is UPDATE_SELECTED, then the function will be called only on the currently selected xform.
 | 
					/// If no xforms are selected via the checkboxes, and the update type is UPDATE_SELECTED, then the function will be called only on the currently selected xform.
 | 
				
			||||||
 | 
					/// If the update type is UPDATE_CURRENT_AND_SELECTED, and the current is not among those selected, then the function will be called on the currently selected xform as well.
 | 
				
			||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
/// <param name="func">The function to call</param>
 | 
					/// <param name="func">The function to call</param>
 | 
				
			||||||
/// <param name="updateType">Whether to apply this update operation on the current, all or selected xforms. Default: eXformUpdate::UPDATE_CURRENT.</param>
 | 
					/// <param name="updateType">Whether to apply this update operation on the current, all or selected xforms. Default: eXformUpdate::UPDATE_CURRENT.</param>
 | 
				
			||||||
@ -240,19 +242,48 @@ void FractoriumEmberController<T>::UpdateXform(std::function<void(Xform<T>*)> fu
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		case eXformUpdate::UPDATE_CURRENT:
 | 
							case eXformUpdate::UPDATE_CURRENT:
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (Xform<T>* xform = CurrentXform())
 | 
								if (auto xform = CurrentXform())
 | 
				
			||||||
				func(xform);
 | 
									func(xform);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case eXformUpdate::UPDATE_CURRENT_AND_SELECTED:
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								bool currentDone = false;
 | 
				
			||||||
 | 
								auto current = CurrentXform();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								while (auto xform = m_Ember.GetTotalXform(i))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (auto child = m_Fractorium->m_XformsSelectionLayout->itemAt(i))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										if (auto* w = qobject_cast<QCheckBox*>(child->widget()))
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											if (w->isChecked())
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												func(xform);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												if (xform == current)
 | 
				
			||||||
 | 
													currentDone = true;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									i++;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!currentDone)//Current was not among those selected, so apply to it.
 | 
				
			||||||
 | 
									func(current);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case eXformUpdate::UPDATE_SELECTED:
 | 
							case eXformUpdate::UPDATE_SELECTED:
 | 
				
			||||||
		case eXformUpdate::UPDATE_SELECTED_EXCEPT_FINAL:
 | 
							case eXformUpdate::UPDATE_SELECTED_EXCEPT_FINAL:
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			bool anyUpdated = false;
 | 
								bool anyUpdated = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			while (Xform<T>* xform = (doFinal ? m_Ember.GetTotalXform(i) : m_Ember.GetXform(i)))
 | 
								while (auto xform = (doFinal ? m_Ember.GetTotalXform(i) : m_Ember.GetXform(i)))
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				if (QLayoutItem* child = m_Fractorium->m_XformsSelectionLayout->itemAt(i))
 | 
									if (auto child = m_Fractorium->m_XformsSelectionLayout->itemAt(i))
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					if (auto* w = qobject_cast<QCheckBox*>(child->widget()))
 | 
										if (auto* w = qobject_cast<QCheckBox*>(child->widget()))
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
@ -269,14 +300,14 @@ void FractoriumEmberController<T>::UpdateXform(std::function<void(Xform<T>*)> fu
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			if (!anyUpdated)//None were selected, so just apply to the current.
 | 
								if (!anyUpdated)//None were selected, so just apply to the current.
 | 
				
			||||||
				if (doFinal || !isCurrentFinal)//If do final, call func regardless. If not, only call if current is not final.
 | 
									if (doFinal || !isCurrentFinal)//If do final, call func regardless. If not, only call if current is not final.
 | 
				
			||||||
					if (Xform<T>* xform = CurrentXform())
 | 
										if (auto xform = CurrentXform())
 | 
				
			||||||
						func(xform);
 | 
											func(xform);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case eXformUpdate::UPDATE_ALL:
 | 
							case eXformUpdate::UPDATE_ALL:
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			while (Xform<T>* xform = m_Ember.GetTotalXform(i++))
 | 
								while (auto xform = m_Ember.GetTotalXform(i++))
 | 
				
			||||||
				func(xform);
 | 
									func(xform);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
@ -284,7 +315,7 @@ void FractoriumEmberController<T>::UpdateXform(std::function<void(Xform<T>*)> fu
 | 
				
			|||||||
		case eXformUpdate::UPDATE_ALL_EXCEPT_FINAL:
 | 
							case eXformUpdate::UPDATE_ALL_EXCEPT_FINAL:
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			while (Xform<T>* xform = m_Ember.GetXform(i++))
 | 
								while (auto xform = m_Ember.GetXform(i++))
 | 
				
			||||||
				func(xform);
 | 
									func(xform);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
@ -325,6 +356,7 @@ void FractoriumEmberController<T>::SetEmberPrivate(const Ember<U>& ember, bool v
 | 
				
			|||||||
	string filename = "last.flame";
 | 
						string filename = "last.flame";
 | 
				
			||||||
	writer.Save(filename.c_str(), m_Ember, 0, true, false, true);
 | 
						writer.Save(filename.c_str(), m_Ember, 0, true, false, true);
 | 
				
			||||||
	m_GLController->ResetMouseState();
 | 
						m_GLController->ResetMouseState();
 | 
				
			||||||
 | 
						m_Fractorium->ui.LockAffineCheckBox->setChecked(false);
 | 
				
			||||||
	FillXforms();//Must do this first because the palette setup in FillParamTablesAndPalette() uses the xforms combo.
 | 
						FillXforms();//Must do this first because the palette setup in FillParamTablesAndPalette() uses the xforms combo.
 | 
				
			||||||
	FillParamTablesAndPalette();
 | 
						FillParamTablesAndPalette();
 | 
				
			||||||
	FillSummary();
 | 
						FillSummary();
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,7 @@ enum class eEditUndoState : et { REGULAR_EDIT, UNDO_REDO, EDIT_UNDO };
 | 
				
			|||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
/// An enum representing which xforms an update should be applied to.
 | 
					/// An enum representing which xforms an update should be applied to.
 | 
				
			||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
enum class eXformUpdate : et { UPDATE_CURRENT, UPDATE_SELECTED, UPDATE_SELECTED_EXCEPT_FINAL, UPDATE_ALL, UPDATE_ALL_EXCEPT_FINAL };
 | 
					enum class eXformUpdate : et { UPDATE_CURRENT, UPDATE_SELECTED, UPDATE_CURRENT_AND_SELECTED, UPDATE_SELECTED_EXCEPT_FINAL, UPDATE_ALL, UPDATE_ALL_EXCEPT_FINAL };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
/// FractoriumEmberController and Fractorium need each other, but each can't include the other.
 | 
					/// FractoriumEmberController and Fractorium need each other, but each can't include the other.
 | 
				
			||||||
@ -161,6 +161,7 @@ public:
 | 
				
			|||||||
	virtual void XformWeightChanged(double d) { }
 | 
						virtual void XformWeightChanged(double d) { }
 | 
				
			||||||
	virtual void EqualizeWeights() { }
 | 
						virtual void EqualizeWeights() { }
 | 
				
			||||||
	virtual void XformNameChanged(int row, int col) { }
 | 
						virtual void XformNameChanged(int row, int col) { }
 | 
				
			||||||
 | 
						virtual void XformAnimateChanged(int state) { }
 | 
				
			||||||
	virtual void FillXforms(int index = 0) { }
 | 
						virtual void FillXforms(int index = 0) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//Xforms Affine.
 | 
						//Xforms Affine.
 | 
				
			||||||
@ -171,6 +172,8 @@ public:
 | 
				
			|||||||
	virtual void ScaleXforms(double scale, bool pre) { }
 | 
						virtual void ScaleXforms(double scale, bool pre) { }
 | 
				
			||||||
	virtual void ResetXformsAffine(bool pre) { }
 | 
						virtual void ResetXformsAffine(bool pre) { }
 | 
				
			||||||
	virtual void FillBothAffines() { }
 | 
						virtual void FillBothAffines() { }
 | 
				
			||||||
 | 
						double LockedScale() { return m_LockedScale; }
 | 
				
			||||||
 | 
						virtual void LockAffineScaleCheckBoxStateChanged(int state) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//Xforms Color.
 | 
						//Xforms Color.
 | 
				
			||||||
	virtual void XformColorIndexChanged(double d, bool updateRender) { }
 | 
						virtual void XformColorIndexChanged(double d, bool updateRender) { }
 | 
				
			||||||
@ -241,6 +244,7 @@ protected:
 | 
				
			|||||||
	uint m_SubBatchCount;
 | 
						uint m_SubBatchCount;
 | 
				
			||||||
	uint m_FailedRenders;
 | 
						uint m_FailedRenders;
 | 
				
			||||||
	uint m_UndoIndex;
 | 
						uint m_UndoIndex;
 | 
				
			||||||
 | 
						double m_LockedScale;
 | 
				
			||||||
	eRendererType m_RenderType;
 | 
						eRendererType m_RenderType;
 | 
				
			||||||
	eEditUndoState m_EditState;
 | 
						eEditUndoState m_EditState;
 | 
				
			||||||
	GLuint m_OutputTexID;
 | 
						GLuint m_OutputTexID;
 | 
				
			||||||
@ -397,9 +401,11 @@ public:
 | 
				
			|||||||
	virtual void XformWeightChanged(double d) override;
 | 
						virtual void XformWeightChanged(double d) override;
 | 
				
			||||||
	virtual void EqualizeWeights() override;
 | 
						virtual void EqualizeWeights() override;
 | 
				
			||||||
	virtual void XformNameChanged(int row, int col) override;
 | 
						virtual void XformNameChanged(int row, int col) override;
 | 
				
			||||||
 | 
						virtual void XformAnimateChanged(int state) override;
 | 
				
			||||||
	virtual void FillXforms(int index = 0) override;
 | 
						virtual void FillXforms(int index = 0) override;
 | 
				
			||||||
	void FillWithXform(Xform<T>* xform);
 | 
						void FillWithXform(Xform<T>* xform);
 | 
				
			||||||
	Xform<T>* CurrentXform();
 | 
						Xform<T>* CurrentXform();
 | 
				
			||||||
 | 
						void UpdateXform(std::function<void(Xform<T>*)> func, eXformUpdate updateType = eXformUpdate::UPDATE_CURRENT, bool updateRender = true, eProcessAction action = eProcessAction::FULL_RENDER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//Xforms Affine.
 | 
						//Xforms Affine.
 | 
				
			||||||
	virtual void AffineSetHelper(double d, int index, bool pre) override;
 | 
						virtual void AffineSetHelper(double d, int index, bool pre) override;
 | 
				
			||||||
@ -409,7 +415,10 @@ public:
 | 
				
			|||||||
	virtual void ScaleXforms(double scale, bool pre) override;
 | 
						virtual void ScaleXforms(double scale, bool pre) override;
 | 
				
			||||||
	virtual void ResetXformsAffine(bool pre) override;
 | 
						virtual void ResetXformsAffine(bool pre) override;
 | 
				
			||||||
	virtual void FillBothAffines() override;
 | 
						virtual void FillBothAffines() override;
 | 
				
			||||||
 | 
						virtual void LockAffineScaleCheckBoxStateChanged(int state) override;
 | 
				
			||||||
	void FillAffineWithXform(Xform<T>* xform, bool pre);
 | 
						void FillAffineWithXform(Xform<T>* xform, bool pre);
 | 
				
			||||||
 | 
						T AffineScaleCurrentToLocked();
 | 
				
			||||||
 | 
						T AffineScaleLockedToCurrent();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//Xforms Color.
 | 
						//Xforms Color.
 | 
				
			||||||
	virtual void XformColorIndexChanged(double d, bool updateRender) override;
 | 
						virtual void XformColorIndexChanged(double d, bool updateRender) override;
 | 
				
			||||||
@ -473,7 +482,6 @@ private:
 | 
				
			|||||||
	QString MakeXformCaption(size_t i);
 | 
						QString MakeXformCaption(size_t i);
 | 
				
			||||||
	bool XformCheckboxAt(int i, std::function<void(QCheckBox*)> func);
 | 
						bool XformCheckboxAt(int i, std::function<void(QCheckBox*)> func);
 | 
				
			||||||
	bool XformCheckboxAt(Xform<T>* xform, std::function<void(QCheckBox*)> func);
 | 
						bool XformCheckboxAt(Xform<T>* xform, std::function<void(QCheckBox*)> func);
 | 
				
			||||||
	void UpdateXform(std::function<void(Xform<T>*)> func, eXformUpdate updateType = eXformUpdate::UPDATE_CURRENT, bool updateRender = true, eProcessAction action = eProcessAction::FULL_RENDER);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//Palette.
 | 
						//Palette.
 | 
				
			||||||
	void UpdateAdjustedPaletteGUI(Palette<T>& palette);
 | 
						void UpdateAdjustedPaletteGUI(Palette<T>& palette);
 | 
				
			||||||
 | 
				
			|||||||
@ -176,7 +176,7 @@ void FractoriumEmberController<T>::OpenAndPrepFiles(const QStringList& filenames
 | 
				
			|||||||
		StopPreviewRender();
 | 
							StopPreviewRender();
 | 
				
			||||||
		emberFile.m_Filename = filenames[0];
 | 
							emberFile.m_Filename = filenames[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		foreach (const QString& filename, filenames)
 | 
							for (auto& filename : filenames)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			embers.clear();
 | 
								embers.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -694,7 +694,7 @@ void Fractorium::OnActionResetWorkspace(bool checked)
 | 
				
			|||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
void FractoriumEmberController<T>::AddReflectiveSymmetry()
 | 
					void FractoriumEmberController<T>::AddReflectiveSymmetry()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	QComboBox* combo = m_Fractorium->ui.CurrentXformCombo;
 | 
						auto combo = m_Fractorium->ui.CurrentXformCombo;
 | 
				
			||||||
	Update([&]()
 | 
						Update([&]()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		m_Ember.AddSymmetry(-1, m_Rand);
 | 
							m_Ember.AddSymmetry(-1, m_Rand);
 | 
				
			||||||
@ -712,7 +712,7 @@ void Fractorium::OnActionAddReflectiveSymmetry(bool checked) { m_Controller->Add
 | 
				
			|||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
void FractoriumEmberController<T>::AddRotationalSymmetry()
 | 
					void FractoriumEmberController<T>::AddRotationalSymmetry()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	QComboBox* combo = m_Fractorium->ui.CurrentXformCombo;
 | 
						auto combo = m_Fractorium->ui.CurrentXformCombo;
 | 
				
			||||||
	Update([&]()
 | 
						Update([&]()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		m_Ember.AddSymmetry(2, m_Rand);
 | 
							m_Ember.AddSymmetry(2, m_Rand);
 | 
				
			||||||
@ -730,7 +730,7 @@ void Fractorium::OnActionAddRotationalSymmetry(bool checked) { m_Controller->Add
 | 
				
			|||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
void FractoriumEmberController<T>::AddBothSymmetry()
 | 
					void FractoriumEmberController<T>::AddBothSymmetry()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	QComboBox* combo = m_Fractorium->ui.CurrentXformCombo;
 | 
						auto combo = m_Fractorium->ui.CurrentXformCombo;
 | 
				
			||||||
	Update([&]()
 | 
						Update([&]()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		m_Ember.AddSymmetry(-2, m_Rand);
 | 
							m_Ember.AddSymmetry(-2, m_Rand);
 | 
				
			||||||
@ -772,7 +772,7 @@ void FractoriumEmberController<T>::ClearFlame()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		if (m_Ember.XformCount() == 1)
 | 
							if (m_Ember.XformCount() == 1)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (Xform<T>* xform = m_Ember.GetXform(0))
 | 
								if (auto xform = m_Ember.GetXform(0))
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				xform->Clear();
 | 
									xform->Clear();
 | 
				
			||||||
				xform->ParentEmber(&m_Ember);
 | 
									xform->ParentEmber(&m_Ember);
 | 
				
			||||||
 | 
				
			|||||||
@ -10,38 +10,30 @@
 | 
				
			|||||||
void Fractorium::InitPaletteUI()
 | 
					void Fractorium::InitPaletteUI()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int spinHeight = 20, row = 0;
 | 
						int spinHeight = 20, row = 0;
 | 
				
			||||||
	QTableWidget* paletteTable = ui.PaletteListTable;
 | 
						auto paletteTable = ui.PaletteListTable;
 | 
				
			||||||
	QTableWidget* palettePreviewTable = ui.PalettePreviewTable;
 | 
						auto palettePreviewTable = ui.PalettePreviewTable;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	connect(ui.PaletteFilenameCombo, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(OnPaletteFilenameComboChanged(const QString&)), Qt::QueuedConnection);
 | 
						connect(ui.PaletteFilenameCombo, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(OnPaletteFilenameComboChanged(const QString&)), Qt::QueuedConnection);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	connect(paletteTable, SIGNAL(cellClicked(int, int)),	   this, SLOT(OnPaletteCellClicked(int, int)),		 Qt::QueuedConnection);
 | 
						connect(paletteTable, SIGNAL(cellClicked(int, int)),	   this, SLOT(OnPaletteCellClicked(int, int)),		 Qt::QueuedConnection);
 | 
				
			||||||
	connect(paletteTable, SIGNAL(cellDoubleClicked(int, int)), this, SLOT(OnPaletteCellDoubleClicked(int, int)), Qt::QueuedConnection);
 | 
						connect(paletteTable, SIGNAL(cellDoubleClicked(int, int)), this, SLOT(OnPaletteCellDoubleClicked(int, int)), Qt::QueuedConnection);
 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	//Palette adjustment table.
 | 
						//Palette adjustment table.
 | 
				
			||||||
	QTableWidget* table = ui.PaletteAdjustTable;
 | 
						auto table = ui.PaletteAdjustTable;
 | 
				
			||||||
	table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);//Split width over all columns evenly.
 | 
						table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);//Split width over all columns evenly.
 | 
				
			||||||
 | 
					 | 
				
			||||||
	SetupSpinner<SpinBox, int>(table, this, row, 1, m_PaletteHueSpin,		 spinHeight, -180, 180, 1, SIGNAL(valueChanged(int)), SLOT(OnPaletteAdjust(int)), true, 0, 0, 0);
 | 
						SetupSpinner<SpinBox, int>(table, this, row, 1, m_PaletteHueSpin,		 spinHeight, -180, 180, 1, SIGNAL(valueChanged(int)), SLOT(OnPaletteAdjust(int)), true, 0, 0, 0);
 | 
				
			||||||
	SetupSpinner<SpinBox, int>(table, this, row, 1, m_PaletteSaturationSpin, spinHeight, -100, 100, 1, SIGNAL(valueChanged(int)), SLOT(OnPaletteAdjust(int)), true, 0, 0, 0);
 | 
						SetupSpinner<SpinBox, int>(table, this, row, 1, m_PaletteSaturationSpin, spinHeight, -100, 100, 1, SIGNAL(valueChanged(int)), SLOT(OnPaletteAdjust(int)), true, 0, 0, 0);
 | 
				
			||||||
	SetupSpinner<SpinBox, int>(table, this, row, 1, m_PaletteBrightnessSpin, spinHeight, -255, 255, 1, SIGNAL(valueChanged(int)), SLOT(OnPaletteAdjust(int)), true, 0, 0, 0);
 | 
						SetupSpinner<SpinBox, int>(table, this, row, 1, m_PaletteBrightnessSpin, spinHeight, -255, 255, 1, SIGNAL(valueChanged(int)), SLOT(OnPaletteAdjust(int)), true, 0, 0, 0);
 | 
				
			||||||
	row = 0;
 | 
						row = 0;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	SetupSpinner<SpinBox, int>(table, this, row, 3, m_PaletteContrastSpin,  spinHeight, -100, 100, 1, SIGNAL(valueChanged(int)), SLOT(OnPaletteAdjust(int)), true, 0, 0, 0);
 | 
						SetupSpinner<SpinBox, int>(table, this, row, 3, m_PaletteContrastSpin,  spinHeight, -100, 100, 1, SIGNAL(valueChanged(int)), SLOT(OnPaletteAdjust(int)), true, 0, 0, 0);
 | 
				
			||||||
	SetupSpinner<SpinBox, int>(table, this, row, 3, m_PaletteBlurSpin,	    spinHeight,	   0, 127, 1, SIGNAL(valueChanged(int)), SLOT(OnPaletteAdjust(int)), true, 0, 0, 0);
 | 
						SetupSpinner<SpinBox, int>(table, this, row, 3, m_PaletteBlurSpin,	    spinHeight,	   0, 127, 1, SIGNAL(valueChanged(int)), SLOT(OnPaletteAdjust(int)), true, 0, 0, 0);
 | 
				
			||||||
	SetupSpinner<SpinBox, int>(table, this, row, 3, m_PaletteFrequencySpin, spinHeight,	   1,  10, 1, SIGNAL(valueChanged(int)), SLOT(OnPaletteAdjust(int)), true, 1, 1, 1);
 | 
						SetupSpinner<SpinBox, int>(table, this, row, 3, m_PaletteFrequencySpin, spinHeight,	   1,  10, 1, SIGNAL(valueChanged(int)), SLOT(OnPaletteAdjust(int)), true, 1, 1, 1);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	connect(ui.PaletteRandomSelect, SIGNAL(clicked(bool)), this, SLOT(OnPaletteRandomSelectButtonClicked(bool)), Qt::QueuedConnection);
 | 
						connect(ui.PaletteRandomSelect, SIGNAL(clicked(bool)), this, SLOT(OnPaletteRandomSelectButtonClicked(bool)), Qt::QueuedConnection);
 | 
				
			||||||
	connect(ui.PaletteRandomAdjust, SIGNAL(clicked(bool)), this, SLOT(OnPaletteRandomAdjustButtonClicked(bool)), Qt::QueuedConnection);
 | 
						connect(ui.PaletteRandomAdjust, SIGNAL(clicked(bool)), this, SLOT(OnPaletteRandomAdjustButtonClicked(bool)), Qt::QueuedConnection);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	//Preview table.
 | 
						//Preview table.
 | 
				
			||||||
	palettePreviewTable->setRowCount(1);
 | 
						palettePreviewTable->setRowCount(1);
 | 
				
			||||||
	palettePreviewTable->setColumnWidth(1, 260);//256 plus small margin on each side.
 | 
						palettePreviewTable->setColumnWidth(1, 260);//256 plus small margin on each side.
 | 
				
			||||||
	QTableWidgetItem* previewNameCol = new QTableWidgetItem("");
 | 
						auto previewNameCol = new QTableWidgetItem("");
 | 
				
			||||||
	palettePreviewTable->setItem(0, 0, previewNameCol);
 | 
						palettePreviewTable->setItem(0, 0, previewNameCol);
 | 
				
			||||||
	QTableWidgetItem* previewPaletteItem = new QTableWidgetItem();
 | 
						auto previewPaletteItem = new QTableWidgetItem();
 | 
				
			||||||
	palettePreviewTable->setItem(0, 1, previewPaletteItem);
 | 
						palettePreviewTable->setItem(0, 1, previewPaletteItem);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	connect(ui.PaletteFilterLineEdit,	 SIGNAL(textChanged(const QString&)), this, SLOT(OnPaletteFilterLineEditTextChanged(const QString&)));
 | 
						connect(ui.PaletteFilterLineEdit,	 SIGNAL(textChanged(const QString&)), this, SLOT(OnPaletteFilterLineEditTextChanged(const QString&)));
 | 
				
			||||||
	connect(ui.PaletteFilterClearButton, SIGNAL(clicked(bool)),				  this, SLOT(OnPaletteFilterClearButtonClicked(bool)));
 | 
						connect(ui.PaletteFilterClearButton, SIGNAL(clicked(bool)),				  this, SLOT(OnPaletteFilterClearButtonClicked(bool)));
 | 
				
			||||||
	paletteTable->setColumnWidth(1, 260);//256 plus small margin on each side.
 | 
						paletteTable->setColumnWidth(1, 260);//256 plus small margin on each side.
 | 
				
			||||||
@ -60,7 +52,6 @@ template <typename T>
 | 
				
			|||||||
int FractoriumEmberController<T>::InitPaletteList(const string& s)
 | 
					int FractoriumEmberController<T>::InitPaletteList(const string& s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	QDirIterator it(s.c_str(), QStringList() << "*.xml", QDir::Files, QDirIterator::FollowSymlinks);
 | 
						QDirIterator it(s.c_str(), QStringList() << "*.xml", QDir::Files, QDirIterator::FollowSymlinks);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	m_PaletteList.Clear();
 | 
						m_PaletteList.Clear();
 | 
				
			||||||
	m_Fractorium->ui.PaletteFilenameCombo->clear();
 | 
						m_Fractorium->ui.PaletteFilenameCombo->clear();
 | 
				
			||||||
	m_Fractorium->ui.PaletteFilenameCombo->setProperty("path", QString::fromStdString(s));
 | 
						m_Fractorium->ui.PaletteFilenameCombo->setProperty("path", QString::fromStdString(s));
 | 
				
			||||||
@ -89,9 +80,8 @@ bool FractoriumEmberController<T>::FillPaletteTable(const string& s)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	if (!s.empty())//This occasionally seems to get called with an empty string for reasons unknown.
 | 
						if (!s.empty())//This occasionally seems to get called with an empty string for reasons unknown.
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		QTableWidget* paletteTable = m_Fractorium->ui.PaletteListTable;
 | 
							auto paletteTable = m_Fractorium->ui.PaletteListTable;
 | 
				
			||||||
		QTableWidget* palettePreviewTable = m_Fractorium->ui.PalettePreviewTable;
 | 
							auto palettePreviewTable = m_Fractorium->ui.PalettePreviewTable;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		m_CurrentPaletteFilePath = m_Fractorium->ui.PaletteFilenameCombo->property("path").toString().toStdString() + "/" + s;
 | 
							m_CurrentPaletteFilePath = m_Fractorium->ui.PaletteFilenameCombo->property("path").toString().toStdString() + "/" + s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (size_t paletteSize = m_PaletteList.Size(m_CurrentPaletteFilePath))
 | 
							if (size_t paletteSize = m_PaletteList.Size(m_CurrentPaletteFilePath))
 | 
				
			||||||
@ -99,14 +89,11 @@ bool FractoriumEmberController<T>::FillPaletteTable(const string& s)
 | 
				
			|||||||
			paletteTable->clear();
 | 
								paletteTable->clear();
 | 
				
			||||||
			paletteTable->blockSignals(true);
 | 
								paletteTable->blockSignals(true);
 | 
				
			||||||
			paletteTable->setRowCount(paletteSize);
 | 
								paletteTable->setRowCount(paletteSize);
 | 
				
			||||||
 | 
					 | 
				
			||||||
			//Headers get removed when clearing, so must re-create here.
 | 
								//Headers get removed when clearing, so must re-create here.
 | 
				
			||||||
			QTableWidgetItem* nameHeader = new QTableWidgetItem("Name");
 | 
								auto nameHeader = new QTableWidgetItem("Name");
 | 
				
			||||||
			QTableWidgetItem* paletteHeader = new QTableWidgetItem("Palette");
 | 
								auto paletteHeader = new QTableWidgetItem("Palette");
 | 
				
			||||||
 | 
					 | 
				
			||||||
			nameHeader->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
 | 
								nameHeader->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
 | 
				
			||||||
			paletteHeader->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
 | 
								paletteHeader->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
 | 
				
			||||||
 | 
					 | 
				
			||||||
			paletteTable->setHorizontalHeaderItem(0, nameHeader);
 | 
								paletteTable->setHorizontalHeaderItem(0, nameHeader);
 | 
				
			||||||
			paletteTable->setHorizontalHeaderItem(1, paletteHeader);
 | 
								paletteTable->setHorizontalHeaderItem(1, paletteHeader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -117,13 +104,10 @@ bool FractoriumEmberController<T>::FillPaletteTable(const string& s)
 | 
				
			|||||||
				{
 | 
									{
 | 
				
			||||||
					auto v = p->MakeRgbPaletteBlock(PALETTE_CELL_HEIGHT);
 | 
										auto v = p->MakeRgbPaletteBlock(PALETTE_CELL_HEIGHT);
 | 
				
			||||||
					auto nameCol = new QTableWidgetItem(p->m_Name.c_str());
 | 
										auto nameCol = new QTableWidgetItem(p->m_Name.c_str());
 | 
				
			||||||
 | 
					 | 
				
			||||||
					nameCol->setToolTip(p->m_Name.c_str());
 | 
										nameCol->setToolTip(p->m_Name.c_str());
 | 
				
			||||||
					paletteTable->setItem(i, 0, nameCol);
 | 
										paletteTable->setItem(i, 0, nameCol);
 | 
				
			||||||
 | 
					 | 
				
			||||||
					QImage image(v.data(), p->Size(), PALETTE_CELL_HEIGHT, QImage::Format_RGB888);
 | 
										QImage image(v.data(), p->Size(), PALETTE_CELL_HEIGHT, QImage::Format_RGB888);
 | 
				
			||||||
					auto paletteItem = new PaletteTableWidgetItem<T>(p);
 | 
										auto paletteItem = new PaletteTableWidgetItem<T>(p);
 | 
				
			||||||
 | 
					 | 
				
			||||||
					paletteItem->setData(Qt::DecorationRole, QPixmap::fromImage(image));
 | 
										paletteItem->setData(Qt::DecorationRole, QPixmap::fromImage(image));
 | 
				
			||||||
					paletteTable->setItem(i, 1, paletteItem);
 | 
										paletteTable->setItem(i, 1, paletteItem);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@ -135,7 +119,6 @@ bool FractoriumEmberController<T>::FillPaletteTable(const string& s)
 | 
				
			|||||||
		else
 | 
							else
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			vector<string> errors = m_PaletteList.ErrorReport();
 | 
								vector<string> errors = m_PaletteList.ErrorReport();
 | 
				
			||||||
 | 
					 | 
				
			||||||
			m_Fractorium->ErrorReportToQTextEdit(errors, m_Fractorium->ui.InfoFileOpeningTextEdit);
 | 
								m_Fractorium->ErrorReportToQTextEdit(errors, m_Fractorium->ui.InfoFileOpeningTextEdit);
 | 
				
			||||||
			m_Fractorium->ShowCritical("Palette Read Error", "Could not load palette file, all images will be black. See info tab for details.");
 | 
								m_Fractorium->ShowCritical("Palette Read Error", "Could not load palette file, all images will be black. See info tab for details.");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -163,7 +146,6 @@ void FractoriumEmberController<T>::ApplyPaletteToEmber()
 | 
				
			|||||||
	double brightness = double(m_Fractorium->m_PaletteBrightnessSpin->value() / 255.0);
 | 
						double brightness = double(m_Fractorium->m_PaletteBrightnessSpin->value() / 255.0);
 | 
				
			||||||
	double contrast = double(m_Fractorium->m_PaletteContrastSpin->value() > 0 ? (m_Fractorium->m_PaletteContrastSpin->value() * 2) : m_Fractorium->m_PaletteContrastSpin->value()) / 100.0;
 | 
						double contrast = double(m_Fractorium->m_PaletteContrastSpin->value() > 0 ? (m_Fractorium->m_PaletteContrastSpin->value() * 2) : m_Fractorium->m_PaletteContrastSpin->value()) / 100.0;
 | 
				
			||||||
	double hue = double(m_Fractorium->m_PaletteHueSpin->value()) / 360.0;
 | 
						double hue = double(m_Fractorium->m_PaletteHueSpin->value()) / 360.0;
 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	//Use the temp palette as the base and apply the adjustments gotten from the GUI and save the result in the ember palette.
 | 
						//Use the temp palette as the base and apply the adjustments gotten from the GUI and save the result in the ember palette.
 | 
				
			||||||
	m_TempPalette.MakeAdjustedPalette(m_Ember.m_Palette, 0, hue, sat, brightness, contrast, blur, freq);
 | 
						m_TempPalette.MakeAdjustedPalette(m_Ember.m_Palette, 0, hue, sat, brightness, contrast, blur, freq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -177,23 +159,21 @@ void FractoriumEmberController<T>::ApplyPaletteToEmber()
 | 
				
			|||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
void FractoriumEmberController<T>::UpdateAdjustedPaletteGUI(Palette<T>& palette)
 | 
					void FractoriumEmberController<T>::UpdateAdjustedPaletteGUI(Palette<T>& palette)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Xform<T>* xform = CurrentXform();
 | 
						auto xform = CurrentXform();
 | 
				
			||||||
	QTableWidget* palettePreviewTable = m_Fractorium->ui.PalettePreviewTable;
 | 
						auto palettePreviewTable = m_Fractorium->ui.PalettePreviewTable;
 | 
				
			||||||
	QTableWidgetItem* previewPaletteItem = palettePreviewTable->item(0, 1);
 | 
						auto previewPaletteItem = palettePreviewTable->item(0, 1);
 | 
				
			||||||
	QString paletteName = QString::fromStdString(m_Ember.m_Palette.m_Name);
 | 
						auto paletteName = QString::fromStdString(m_Ember.m_Palette.m_Name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (previewPaletteItem)//This can be null if the palette file was moved or corrupted.
 | 
						if (previewPaletteItem)//This can be null if the palette file was moved or corrupted.
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		//Use the adjusted palette to fill the preview palette control so the user can see the effects of applying the adjustements.
 | 
							//Use the adjusted palette to fill the preview palette control so the user can see the effects of applying the adjustements.
 | 
				
			||||||
		vector<byte> v = palette.MakeRgbPaletteBlock(PALETTE_CELL_HEIGHT);//Make the palette repeat for PALETTE_CELL_HEIGHT rows.
 | 
							vector<byte> v = palette.MakeRgbPaletteBlock(PALETTE_CELL_HEIGHT);//Make the palette repeat for PALETTE_CELL_HEIGHT rows.
 | 
				
			||||||
 | 
					 | 
				
			||||||
		m_FinalPaletteImage = QImage(palette.Size(), PALETTE_CELL_HEIGHT, QImage::Format_RGB888);//Create a QImage out of it.
 | 
							m_FinalPaletteImage = QImage(palette.Size(), PALETTE_CELL_HEIGHT, QImage::Format_RGB888);//Create a QImage out of it.
 | 
				
			||||||
		memcpy(m_FinalPaletteImage.scanLine(0), v.data(), v.size() * sizeof(v[0]));//Memcpy the data in.
 | 
							memcpy(m_FinalPaletteImage.scanLine(0), v.data(), v.size() * sizeof(v[0]));//Memcpy the data in.
 | 
				
			||||||
		QPixmap pixmap = QPixmap::fromImage(m_FinalPaletteImage);//Create a QPixmap out of the QImage.
 | 
							auto pixmap = QPixmap::fromImage(m_FinalPaletteImage);//Create a QPixmap out of the QImage.
 | 
				
			||||||
		previewPaletteItem->setData(Qt::DecorationRole, pixmap.scaled(QSize(pixmap.width(), palettePreviewTable->rowHeight(0) + 2), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));//Set the pixmap on the palette tab.
 | 
							previewPaletteItem->setData(Qt::DecorationRole, pixmap.scaled(QSize(pixmap.width(), palettePreviewTable->rowHeight(0) + 2), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));//Set the pixmap on the palette tab.
 | 
				
			||||||
		m_Fractorium->SetPaletteTableItem(&pixmap, m_Fractorium->ui.XformPaletteRefTable, m_Fractorium->m_PaletteRefItem, 0, 0);//Set the palette ref table on the xforms | color tab.
 | 
							m_Fractorium->SetPaletteTableItem(&pixmap, m_Fractorium->ui.XformPaletteRefTable, m_Fractorium->m_PaletteRefItem, 0, 0);//Set the palette ref table on the xforms | color tab.
 | 
				
			||||||
 | 
							auto previewNameItem = palettePreviewTable->item(0, 0);
 | 
				
			||||||
		QTableWidgetItem* previewNameItem = palettePreviewTable->item(0, 0);
 | 
					 | 
				
			||||||
		previewNameItem->setText(paletteName);//Finally, set the name of the palette to be both the text and the tooltip.
 | 
							previewNameItem->setText(paletteName);//Finally, set the name of the palette to be both the text and the tooltip.
 | 
				
			||||||
		previewNameItem->setToolTip(paletteName);
 | 
							previewNameItem->setToolTip(paletteName);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -308,7 +288,6 @@ void Fractorium::OnPaletteRandomSelectButtonClicked(bool checked)
 | 
				
			|||||||
void Fractorium::OnPaletteRandomAdjustButtonClicked(bool checked)
 | 
					void Fractorium::OnPaletteRandomAdjustButtonClicked(bool checked)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	QTIsaac<ISAAC_SIZE, ISAAC_INT>* gRand = QTIsaac<ISAAC_SIZE, ISAAC_INT>::GlobalRand.get();
 | 
						QTIsaac<ISAAC_SIZE, ISAAC_INT>* gRand = QTIsaac<ISAAC_SIZE, ISAAC_INT>::GlobalRand.get();
 | 
				
			||||||
 | 
					 | 
				
			||||||
	m_PaletteHueSpin->setValue(-180 + gRand->Rand(361));
 | 
						m_PaletteHueSpin->setValue(-180 + gRand->Rand(361));
 | 
				
			||||||
	m_PaletteSaturationSpin->setValue(-50 + gRand->Rand(101));//Full range of these leads to bad palettes, so clamp range.
 | 
						m_PaletteSaturationSpin->setValue(-50 + gRand->Rand(101));//Full range of these leads to bad palettes, so clamp range.
 | 
				
			||||||
	m_PaletteBrightnessSpin->setValue(-50 + gRand->Rand(101));
 | 
						m_PaletteBrightnessSpin->setValue(-50 + gRand->Rand(101));
 | 
				
			||||||
@ -338,7 +317,6 @@ void Fractorium::OnPaletteRandomAdjustButtonClicked(bool checked)
 | 
				
			|||||||
void Fractorium::OnPaletteFilterLineEditTextChanged(const QString& text)
 | 
					void Fractorium::OnPaletteFilterLineEditTextChanged(const QString& text)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto table = ui.PaletteListTable;
 | 
						auto table = ui.PaletteListTable;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	table->setUpdatesEnabled(false);
 | 
						table->setUpdatesEnabled(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (int i = 0; i < table->rowCount(); i++)
 | 
						for (int i = 0; i < table->rowCount(); i++)
 | 
				
			||||||
 | 
				
			|||||||
@ -167,12 +167,12 @@ void FractoriumEmberController<T>::BackgroundChanged(const QColor& color)
 | 
				
			|||||||
	Update([&]
 | 
						Update([&]
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int itemRow = 5;
 | 
							int itemRow = 5;
 | 
				
			||||||
		QTableWidget* colorTable = m_Fractorium->ui.ColorTable;
 | 
							auto colorTable = m_Fractorium->ui.ColorTable;
 | 
				
			||||||
		colorTable->item(itemRow, 1)->setBackgroundColor(color);
 | 
							colorTable->item(itemRow, 1)->setBackgroundColor(color);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		QString r = ToString(color.red());
 | 
							auto r = ToString(color.red());
 | 
				
			||||||
		QString g = ToString(color.green());
 | 
							auto g = ToString(color.green());
 | 
				
			||||||
		QString b = ToString(color.blue());
 | 
							auto b = ToString(color.blue());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		colorTable->item(itemRow, 1)->setTextColor(VisibleColor(color));
 | 
							colorTable->item(itemRow, 1)->setTextColor(VisibleColor(color));
 | 
				
			||||||
		colorTable->item(itemRow, 1)->setText("rgb(" + r + ", " + g + ", " + b + ")");
 | 
							colorTable->item(itemRow, 1)->setText("rgb(" + r + ", " + g + ", " + b + ")");
 | 
				
			||||||
 | 
				
			|||||||
@ -56,7 +56,7 @@ void FractoriumEmberController<T>::FillXaos()
 | 
				
			|||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
QString FractoriumEmberController<T>::MakeXaosNameString(uint i)
 | 
					QString FractoriumEmberController<T>::MakeXaosNameString(uint i)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Xform<T>* xform = m_Ember.GetXform(i);
 | 
						auto xform = m_Ember.GetXform(i);
 | 
				
			||||||
	QString name;
 | 
						QString name;
 | 
				
			||||||
	//if (xform)
 | 
						//if (xform)
 | 
				
			||||||
	//{
 | 
						//{
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,6 @@
 | 
				
			|||||||
void Fractorium::InitXformsUI()
 | 
					void Fractorium::InitXformsUI()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int spinHeight = 20, row = 0;
 | 
						int spinHeight = 20, row = 0;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	connect(ui.AddXformButton,		 SIGNAL(clicked(bool)),			   this, SLOT(OnAddXformButtonClicked(bool)),	    Qt::QueuedConnection);
 | 
						connect(ui.AddXformButton,		 SIGNAL(clicked(bool)),			   this, SLOT(OnAddXformButtonClicked(bool)),	    Qt::QueuedConnection);
 | 
				
			||||||
	connect(ui.AddLinkedXformButton, SIGNAL(clicked(bool)),			   this, SLOT(OnAddLinkedXformButtonClicked(bool)),	Qt::QueuedConnection);
 | 
						connect(ui.AddLinkedXformButton, SIGNAL(clicked(bool)),			   this, SLOT(OnAddLinkedXformButtonClicked(bool)),	Qt::QueuedConnection);
 | 
				
			||||||
	connect(ui.DuplicateXformButton, SIGNAL(clicked(bool)),			   this, SLOT(OnDuplicateXformButtonClicked(bool)),	Qt::QueuedConnection);
 | 
						connect(ui.DuplicateXformButton, SIGNAL(clicked(bool)),			   this, SLOT(OnDuplicateXformButtonClicked(bool)),	Qt::QueuedConnection);
 | 
				
			||||||
@ -15,7 +14,7 @@ void Fractorium::InitXformsUI()
 | 
				
			|||||||
	connect(ui.DeleteXformButton,	 SIGNAL(clicked(bool)),			   this, SLOT(OnDeleteXformButtonClicked(bool)),    Qt::QueuedConnection);
 | 
						connect(ui.DeleteXformButton,	 SIGNAL(clicked(bool)),			   this, SLOT(OnDeleteXformButtonClicked(bool)),    Qt::QueuedConnection);
 | 
				
			||||||
	connect(ui.AddFinalXformButton,  SIGNAL(clicked(bool)),			   this, SLOT(OnAddFinalXformButtonClicked(bool)),  Qt::QueuedConnection);
 | 
						connect(ui.AddFinalXformButton,  SIGNAL(clicked(bool)),			   this, SLOT(OnAddFinalXformButtonClicked(bool)),  Qt::QueuedConnection);
 | 
				
			||||||
	connect(ui.CurrentXformCombo,	 SIGNAL(currentIndexChanged(int)), this, SLOT(OnCurrentXformComboChanged(int)),	    Qt::QueuedConnection);
 | 
						connect(ui.CurrentXformCombo,	 SIGNAL(currentIndexChanged(int)), this, SLOT(OnCurrentXformComboChanged(int)),	    Qt::QueuedConnection);
 | 
				
			||||||
 | 
						connect(ui.AnimateXformCheckBox, SIGNAL(stateChanged(int)),        this, SLOT(OnXformAnimateCheckBoxStateChanged(int)), Qt::QueuedConnection);
 | 
				
			||||||
	SetFixedTableHeader(ui.XformWeightNameTable->horizontalHeader());
 | 
						SetFixedTableHeader(ui.XformWeightNameTable->horizontalHeader());
 | 
				
			||||||
	//Use SetupSpinner() just to create the spinner, but use col of -1 to prevent it from being added to the table.
 | 
						//Use SetupSpinner() just to create the spinner, but use col of -1 to prevent it from being added to the table.
 | 
				
			||||||
	SetupSpinner<DoubleSpinBox, double>(ui.XformWeightNameTable, this, row, -1, m_XformWeightSpin, spinHeight, 0, 1000, 0.05, SIGNAL(valueChanged(double)), SLOT(OnXformWeightChanged(double)), false, 0, 1, 0);
 | 
						SetupSpinner<DoubleSpinBox, double>(ui.XformWeightNameTable, this, row, -1, m_XformWeightSpin, spinHeight, 0, 1000, 0.05, SIGNAL(valueChanged(double)), SLOT(OnXformWeightChanged(double)), false, 0, 1, 0);
 | 
				
			||||||
@ -25,11 +24,9 @@ void Fractorium::InitXformsUI()
 | 
				
			|||||||
	m_XformWeightSpinnerButtonWidget->m_Button->setToolTip("Equalize weights");
 | 
						m_XformWeightSpinnerButtonWidget->m_Button->setToolTip("Equalize weights");
 | 
				
			||||||
	m_XformWeightSpinnerButtonWidget->m_Button->setStyleSheet("text-align: center center");
 | 
						m_XformWeightSpinnerButtonWidget->m_Button->setStyleSheet("text-align: center center");
 | 
				
			||||||
	connect(m_XformWeightSpinnerButtonWidget->m_Button, SIGNAL(clicked(bool)), this, SLOT(OnEqualWeightButtonClicked(bool)), Qt::QueuedConnection);
 | 
						connect(m_XformWeightSpinnerButtonWidget->m_Button, SIGNAL(clicked(bool)), this, SLOT(OnEqualWeightButtonClicked(bool)), Qt::QueuedConnection);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	ui.XformWeightNameTable->setCellWidget(0, 0, m_XformWeightSpinnerButtonWidget);
 | 
						ui.XformWeightNameTable->setCellWidget(0, 0, m_XformWeightSpinnerButtonWidget);
 | 
				
			||||||
	ui.XformWeightNameTable->setItem(0, 1, new QTableWidgetItem());
 | 
						ui.XformWeightNameTable->setItem(0, 1, new QTableWidgetItem());
 | 
				
			||||||
	connect(ui.XformWeightNameTable, SIGNAL(cellChanged(int, int)), this, SLOT(OnXformNameChanged(int, int)), Qt::QueuedConnection);
 | 
						connect(ui.XformWeightNameTable, SIGNAL(cellChanged(int, int)), this, SLOT(OnXformNameChanged(int, int)), Qt::QueuedConnection);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	ui.CurrentXformCombo->setProperty("soloxform", -1);
 | 
						ui.CurrentXformCombo->setProperty("soloxform", -1);
 | 
				
			||||||
#ifndef WIN32
 | 
					#ifndef WIN32
 | 
				
			||||||
	//For some reason linux makes these 24x24, even though the designer explicitly says 16x16.
 | 
						//For some reason linux makes these 24x24, even though the designer explicitly says 16x16.
 | 
				
			||||||
@ -70,19 +67,15 @@ void Fractorium::CurrentXform(uint i)
 | 
				
			|||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
void FractoriumEmberController<T>::CurrentXformComboChanged(int index)
 | 
					void FractoriumEmberController<T>::CurrentXformComboChanged(int index)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (Xform<T>* xform = m_Ember.GetTotalXform(index))
 | 
						if (auto xform = m_Ember.GetTotalXform(index))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		FillWithXform(xform);
 | 
							FillWithXform(xform);
 | 
				
			||||||
		m_GLController->SetSelectedXform(xform);
 | 
							m_GLController->SetSelectedXform(xform);
 | 
				
			||||||
 | 
					 | 
				
			||||||
		int solo = m_Fractorium->ui.CurrentXformCombo->property("soloxform").toInt();
 | 
							int solo = m_Fractorium->ui.CurrentXformCombo->property("soloxform").toInt();
 | 
				
			||||||
 | 
					 | 
				
			||||||
		m_Fractorium->ui.SoloXformCheckBox->blockSignals(true);
 | 
							m_Fractorium->ui.SoloXformCheckBox->blockSignals(true);
 | 
				
			||||||
		m_Fractorium->ui.SoloXformCheckBox->setChecked(solo == index);
 | 
							m_Fractorium->ui.SoloXformCheckBox->setChecked(solo == index);
 | 
				
			||||||
		m_Fractorium->ui.SoloXformCheckBox->blockSignals(false);
 | 
							m_Fractorium->ui.SoloXformCheckBox->blockSignals(false);
 | 
				
			||||||
 | 
					 | 
				
			||||||
		bool enable = !IsFinal(CurrentXform());
 | 
							bool enable = !IsFinal(CurrentXform());
 | 
				
			||||||
 | 
					 | 
				
			||||||
		m_Fractorium->ui.DuplicateXformButton->setEnabled(enable);
 | 
							m_Fractorium->ui.DuplicateXformButton->setEnabled(enable);
 | 
				
			||||||
		m_Fractorium->m_XformWeightSpin->setEnabled(enable);
 | 
							m_Fractorium->m_XformWeightSpin->setEnabled(enable);
 | 
				
			||||||
		m_Fractorium->ui.SoloXformCheckBox->setEnabled(enable);
 | 
							m_Fractorium->ui.SoloXformCheckBox->setEnabled(enable);
 | 
				
			||||||
@ -105,7 +98,6 @@ void FractoriumEmberController<T>::AddXform()
 | 
				
			|||||||
	Update([&]()
 | 
						Update([&]()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Xform<T> newXform;
 | 
							Xform<T> newXform;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		newXform.m_Weight = 0.25;
 | 
							newXform.m_Weight = 0.25;
 | 
				
			||||||
		newXform.m_ColorX = m_Rand.Frand01<T>();
 | 
							newXform.m_ColorX = m_Rand.Frand01<T>();
 | 
				
			||||||
		m_Ember.AddXform(newXform);
 | 
							m_Ember.AddXform(newXform);
 | 
				
			||||||
@ -131,7 +123,6 @@ void FractoriumEmberController<T>::AddLinkedXform()
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		size_t i, count = m_Ember.XformCount();
 | 
							size_t i, count = m_Ember.XformCount();
 | 
				
			||||||
		Xform<T> newXform;
 | 
							Xform<T> newXform;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		newXform.m_Weight = 0.5;
 | 
							newXform.m_Weight = 0.5;
 | 
				
			||||||
		newXform.m_Opacity = 1;
 | 
							newXform.m_Opacity = 1;
 | 
				
			||||||
		newXform.m_ColorSpeed = 1;
 | 
							newXform.m_ColorSpeed = 1;
 | 
				
			||||||
@ -175,17 +166,14 @@ template <typename T>
 | 
				
			|||||||
void FractoriumEmberController<T>::DuplicateXform()
 | 
					void FractoriumEmberController<T>::DuplicateXform()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	vector<Xform<T>> vec;
 | 
						vector<Xform<T>> vec;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	vec.reserve(m_Ember.XformCount());
 | 
						vec.reserve(m_Ember.XformCount());
 | 
				
			||||||
 | 
					 | 
				
			||||||
	UpdateXform([&] (Xform<T>* xform)
 | 
						UpdateXform([&] (Xform<T>* xform)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		vec.push_back(*xform);
 | 
							vec.push_back(*xform);
 | 
				
			||||||
	}, eXformUpdate::UPDATE_SELECTED_EXCEPT_FINAL, false);
 | 
						}, eXformUpdate::UPDATE_SELECTED_EXCEPT_FINAL, false);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	Update([&]()
 | 
						Update([&]()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		QComboBox* combo = m_Fractorium->ui.CurrentXformCombo;
 | 
							auto combo = m_Fractorium->ui.CurrentXformCombo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (auto& it : vec)
 | 
							for (auto& it : vec)
 | 
				
			||||||
			m_Ember.AddXform(it);
 | 
								m_Ember.AddXform(it);
 | 
				
			||||||
@ -210,7 +198,6 @@ void FractoriumEmberController<T>::ClearXform()
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		xform->ClearAndDeleteVariations();//Note xaos is left alone.
 | 
							xform->ClearAndDeleteVariations();//Note xaos is left alone.
 | 
				
			||||||
	}, eXformUpdate::UPDATE_SELECTED);
 | 
						}, eXformUpdate::UPDATE_SELECTED);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	FillVariationTreeWithXform(CurrentXform());
 | 
						FillVariationTreeWithXform(CurrentXform());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -229,8 +216,7 @@ void FractoriumEmberController<T>::DeleteXforms()
 | 
				
			|||||||
	int i = 0, offset = 0, current = 0, checked = 0;
 | 
						int i = 0, offset = 0, current = 0, checked = 0;
 | 
				
			||||||
	bool haveFinal = false;
 | 
						bool haveFinal = false;
 | 
				
			||||||
	size_t count;
 | 
						size_t count;
 | 
				
			||||||
	QComboBox* combo = m_Fractorium->ui.CurrentXformCombo;
 | 
						auto combo = m_Fractorium->ui.CurrentXformCombo;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	//Iterating over the checkboxes must be done instead of using UpdateXform() to iterate over xforms
 | 
						//Iterating over the checkboxes must be done instead of using UpdateXform() to iterate over xforms
 | 
				
			||||||
	//because xforms are being deleted inside the loop.
 | 
						//because xforms are being deleted inside the loop.
 | 
				
			||||||
	//Also manually calling UpdateRender() rather than using the usual Update() call because
 | 
						//Also manually calling UpdateRender() rather than using the usual Update() call because
 | 
				
			||||||
@ -252,12 +238,10 @@ void FractoriumEmberController<T>::DeleteXforms()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		if (w->isChecked())
 | 
							if (w->isChecked())
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			//qDebug() << "Deleting " << w->text();
 | 
					 | 
				
			||||||
			m_Ember.DeleteTotalXform(i - offset);//Subtract offset to account for previously deleted xforms.
 | 
								m_Ember.DeleteTotalXform(i - offset);//Subtract offset to account for previously deleted xforms.
 | 
				
			||||||
			offset++;
 | 
								offset++;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
 | 
					 | 
				
			||||||
	current = combo->currentIndex();
 | 
						current = combo->currentIndex();
 | 
				
			||||||
	count = m_Ember.TotalXformCount();
 | 
						count = m_Ember.TotalXformCount();
 | 
				
			||||||
	haveFinal = m_Ember.UseFinalXform();//Requery again.
 | 
						haveFinal = m_Ember.UseFinalXform();//Requery again.
 | 
				
			||||||
@ -298,7 +282,6 @@ void FractoriumEmberController<T>::AddFinalXform()
 | 
				
			|||||||
		{
 | 
							{
 | 
				
			||||||
			Xform<T> final;
 | 
								Xform<T> final;
 | 
				
			||||||
			auto combo = m_Fractorium->ui.CurrentXformCombo;
 | 
								auto combo = m_Fractorium->ui.CurrentXformCombo;
 | 
				
			||||||
 | 
					 | 
				
			||||||
			final.AddVariation(new LinearVariation<T>());//Just a placeholder so other parts of the code don't see it as being empty.
 | 
								final.AddVariation(new LinearVariation<T>());//Just a placeholder so other parts of the code don't see it as being empty.
 | 
				
			||||||
			m_Ember.SetFinalXform(final);
 | 
								m_Ember.SetFinalXform(final);
 | 
				
			||||||
			int index = m_Ember.TotalXformCount() - 1;//Set index to the last item.
 | 
								int index = m_Ember.TotalXformCount() - 1;//Set index to the last item.
 | 
				
			||||||
@ -322,7 +305,6 @@ void FractoriumEmberController<T>::XformWeightChanged(double d)
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		xform->m_Weight = d;
 | 
							xform->m_Weight = d;
 | 
				
			||||||
	}, eXformUpdate::UPDATE_SELECTED_EXCEPT_FINAL);
 | 
						}, eXformUpdate::UPDATE_SELECTED_EXCEPT_FINAL);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	SetNormalizedWeightText(CurrentXform());
 | 
						SetNormalizedWeightText(CurrentXform());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -356,19 +338,32 @@ void FractoriumEmberController<T>::XformNameChanged(int row, int col)
 | 
				
			|||||||
	UpdateXform([&] (Xform<T>* xform)
 | 
						UpdateXform([&] (Xform<T>* xform)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int index = m_Ember.GetTotalXformIndex(xform);
 | 
							int index = m_Ember.GetTotalXformIndex(xform);
 | 
				
			||||||
 | 
					 | 
				
			||||||
		xform->m_Name = m_Fractorium->ui.XformWeightNameTable->item(row, col)->text().toStdString();
 | 
							xform->m_Name = m_Fractorium->ui.XformWeightNameTable->item(row, col)->text().toStdString();
 | 
				
			||||||
		XformCheckboxAt(index, [&](QCheckBox * checkbox) { checkbox->setText(MakeXformCaption(index)); });
 | 
							XformCheckboxAt(index, [&](QCheckBox * checkbox) { checkbox->setText(MakeXformCaption(index)); });
 | 
				
			||||||
		//if (index != -1)
 | 
					 | 
				
			||||||
		//{
 | 
					 | 
				
			||||||
		//	if (QTableWidgetItem* xformNameItem = m_Fractorium->ui.XaosTable->item(index, 0))
 | 
					 | 
				
			||||||
		//		xformNameItem->setText(MakeXaosNameString(index));
 | 
					 | 
				
			||||||
		//}
 | 
					 | 
				
			||||||
	}, eXformUpdate::UPDATE_CURRENT, false);
 | 
						}, eXformUpdate::UPDATE_CURRENT, false);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Fractorium::OnXformNameChanged(int row, int col) { m_Controller->XformNameChanged(row, col); }
 | 
					void Fractorium::OnXformNameChanged(int row, int col) { m_Controller->XformNameChanged(row, col); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Set the animate field of the selected xforms.
 | 
				
			||||||
 | 
					/// This has no effect on interactive rendering, it only sets a value
 | 
				
			||||||
 | 
					/// that will later be saved to Xml when the user saves.
 | 
				
			||||||
 | 
					/// This value is observed when creating sequences for animation.
 | 
				
			||||||
 | 
					/// Called when the user toggles the animate xform checkbox.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					/// <param name="state">1 for checked, else false</param>
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					void FractoriumEmberController<T>::XformAnimateChanged(int state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						UpdateXform([&](Xform<T>* xform)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							xform->m_Animate = state > 0 ? 1 : 0;
 | 
				
			||||||
 | 
						}, eXformUpdate::UPDATE_SELECTED, false);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Fractorium::OnXformAnimateCheckBoxStateChanged(int state) { m_Controller->XformAnimateChanged(state); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
/// Fill all GUI widgets with values from the passed in xform.
 | 
					/// Fill all GUI widgets with values from the passed in xform.
 | 
				
			||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
@ -378,8 +373,9 @@ void FractoriumEmberController<T>::FillWithXform(Xform<T>* xform)//Need to see w
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	m_Fractorium->m_XformWeightSpin->SetValueStealth(xform->m_Weight);
 | 
						m_Fractorium->m_XformWeightSpin->SetValueStealth(xform->m_Weight);
 | 
				
			||||||
	SetNormalizedWeightText(xform);
 | 
						SetNormalizedWeightText(xform);
 | 
				
			||||||
 | 
						m_Fractorium->ui.AnimateXformCheckBox->setChecked(xform->m_Animate > 0 ? true : false);//Make a signal/slot to handle checking this.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (QTableWidgetItem* item = m_Fractorium->ui.XformWeightNameTable->item(0, 1))
 | 
						if (auto item = m_Fractorium->ui.XformWeightNameTable->item(0, 1))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		m_Fractorium->ui.XformWeightNameTable->blockSignals(true);
 | 
							m_Fractorium->ui.XformWeightNameTable->blockSignals(true);
 | 
				
			||||||
		item->setText(QString::fromStdString(xform->m_Name));
 | 
							item->setText(QString::fromStdString(xform->m_Name));
 | 
				
			||||||
@ -402,7 +398,6 @@ void FractoriumEmberController<T>::SetNormalizedWeightText(Xform<T>* xform)
 | 
				
			|||||||
	if (xform)
 | 
						if (xform)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int index = m_Ember.GetXformIndex(xform);
 | 
							int index = m_Ember.GetXformIndex(xform);
 | 
				
			||||||
 | 
					 | 
				
			||||||
		m_Ember.CalcNormalizedWeights(m_NormalizedWeights);
 | 
							m_Ember.CalcNormalizedWeights(m_NormalizedWeights);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (index != -1 && index < m_NormalizedWeights.size())
 | 
							if (index != -1 && index < m_NormalizedWeights.size())
 | 
				
			||||||
@ -433,10 +428,8 @@ void FractoriumEmberController<T>::FillXforms(int index)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	int i = 0, count = int(XformCount());
 | 
						int i = 0, count = int(XformCount());
 | 
				
			||||||
	auto combo = m_Fractorium->ui.CurrentXformCombo;
 | 
						auto combo = m_Fractorium->ui.CurrentXformCombo;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	combo->blockSignals(true);
 | 
						combo->blockSignals(true);
 | 
				
			||||||
	combo->clear();
 | 
						combo->clear();
 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	//First clear all dynamically created checkboxes.
 | 
						//First clear all dynamically created checkboxes.
 | 
				
			||||||
	m_Fractorium->ClearXformsSelections();
 | 
						m_Fractorium->ClearXformsSelections();
 | 
				
			||||||
	m_Fractorium->m_XformsSelectionLayout->blockSignals(true);
 | 
						m_Fractorium->m_XformsSelectionLayout->blockSignals(true);
 | 
				
			||||||
@ -449,13 +442,13 @@ void FractoriumEmberController<T>::FillXforms(int index)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	i = 0;
 | 
						i = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (i < count)
 | 
						while (i < count)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (i < count - 1)
 | 
							if (i < count - 1)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			auto cb1 = new QCheckBox(MakeXformCaption(i), m_Fractorium);
 | 
								auto cb1 = new QCheckBox(MakeXformCaption(i), m_Fractorium);
 | 
				
			||||||
			auto cb2 = new QCheckBox(MakeXformCaption(i + 1), m_Fractorium);
 | 
								auto cb2 = new QCheckBox(MakeXformCaption(i + 1), m_Fractorium);
 | 
				
			||||||
	
 | 
					 | 
				
			||||||
			m_Fractorium->m_XformSelections.push_back(cb1);
 | 
								m_Fractorium->m_XformSelections.push_back(cb1);
 | 
				
			||||||
			m_Fractorium->m_XformSelections.push_back(cb2);
 | 
								m_Fractorium->m_XformSelections.push_back(cb2);
 | 
				
			||||||
			m_Fractorium->m_XformsSelectionLayout->addRow(cb1, cb2);
 | 
								m_Fractorium->m_XformsSelectionLayout->addRow(cb1, cb2);
 | 
				
			||||||
@ -464,7 +457,6 @@ void FractoriumEmberController<T>::FillXforms(int index)
 | 
				
			|||||||
		else if (i < count)
 | 
							else if (i < count)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			auto cb = new QCheckBox(MakeXformCaption(i), m_Fractorium);
 | 
								auto cb = new QCheckBox(MakeXformCaption(i), m_Fractorium);
 | 
				
			||||||
	
 | 
					 | 
				
			||||||
			m_Fractorium->m_XformSelections.push_back(cb);
 | 
								m_Fractorium->m_XformSelections.push_back(cb);
 | 
				
			||||||
			m_Fractorium->m_XformsSelectionLayout->addRow(cb, new QWidget(m_Fractorium));
 | 
								m_Fractorium->m_XformsSelectionLayout->addRow(cb, new QWidget(m_Fractorium));
 | 
				
			||||||
			i++;
 | 
								i++;
 | 
				
			||||||
@ -475,10 +467,8 @@ void FractoriumEmberController<T>::FillXforms(int index)
 | 
				
			|||||||
	if (UseFinalXform())
 | 
						if (UseFinalXform())
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		auto cb = new QCheckBox(MakeXformCaption(i), m_Fractorium);
 | 
							auto cb = new QCheckBox(MakeXformCaption(i), m_Fractorium);
 | 
				
			||||||
	
 | 
					 | 
				
			||||||
		m_Fractorium->m_XformSelections.push_back(cb);
 | 
							m_Fractorium->m_XformSelections.push_back(cb);
 | 
				
			||||||
		m_Fractorium->m_XformsSelectionLayout->addRow(cb, new QWidget(m_Fractorium));
 | 
							m_Fractorium->m_XformsSelectionLayout->addRow(cb, new QWidget(m_Fractorium));
 | 
				
			||||||
	
 | 
					 | 
				
			||||||
		combo->addItem("Final");
 | 
							combo->addItem("Final");
 | 
				
			||||||
		combo->setItemIcon(i, m_Fractorium->m_FinalXformComboIcon);
 | 
							combo->setItemIcon(i, m_Fractorium->m_FinalXformComboIcon);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -8,8 +8,8 @@ void Fractorium::InitXformsAffineUI()
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	int row = 0, affinePrec = 6, spinHeight = 20;
 | 
						int row = 0, affinePrec = 6, spinHeight = 20;
 | 
				
			||||||
	double affineStep = 0.01, affineMin = std::numeric_limits<double>::lowest(), affineMax = std::numeric_limits<double>::max();
 | 
						double affineStep = 0.01, affineMin = std::numeric_limits<double>::lowest(), affineMax = std::numeric_limits<double>::max();
 | 
				
			||||||
	QTableWidget* table = ui.PreAffineTable;
 | 
						auto table = ui.PreAffineTable;
 | 
				
			||||||
 | 
						connect(ui.LockAffineCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnLockAffineScaleCheckBoxStateChanged(int)), Qt::QueuedConnection);
 | 
				
			||||||
	table->verticalHeader()->setVisible(true);//The designer continually clobbers these values, so must manually set them here.
 | 
						table->verticalHeader()->setVisible(true);//The designer continually clobbers these values, so must manually set them here.
 | 
				
			||||||
	table->horizontalHeader()->setVisible(true);
 | 
						table->horizontalHeader()->setVisible(true);
 | 
				
			||||||
	table->verticalHeader()->setSectionsClickable(true);
 | 
						table->verticalHeader()->setSectionsClickable(true);
 | 
				
			||||||
@ -18,7 +18,6 @@ void Fractorium::InitXformsAffineUI()
 | 
				
			|||||||
	table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
 | 
						table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
 | 
				
			||||||
	connect(table->verticalHeader(),   SIGNAL(sectionDoubleClicked(int)), this, SLOT(OnPreAffineRowDoubleClicked(int)), Qt::QueuedConnection);
 | 
						connect(table->verticalHeader(),   SIGNAL(sectionDoubleClicked(int)), this, SLOT(OnPreAffineRowDoubleClicked(int)), Qt::QueuedConnection);
 | 
				
			||||||
	connect(table->horizontalHeader(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(OnPreAffineColDoubleClicked(int)), Qt::QueuedConnection);
 | 
						connect(table->horizontalHeader(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(OnPreAffineColDoubleClicked(int)), Qt::QueuedConnection);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	//Pre affine spinners.
 | 
						//Pre affine spinners.
 | 
				
			||||||
	SetupAffineSpinner(table, this, 0, 0, m_PreX1Spin, spinHeight, affineMin, affineMax, affineStep, affinePrec, SIGNAL(valueChanged(double)), SLOT(OnX1Changed(double)));
 | 
						SetupAffineSpinner(table, this, 0, 0, m_PreX1Spin, spinHeight, affineMin, affineMax, affineStep, affinePrec, SIGNAL(valueChanged(double)), SLOT(OnX1Changed(double)));
 | 
				
			||||||
	SetupAffineSpinner(table, this, 0, 1, m_PreX2Spin, spinHeight, affineMin, affineMax, affineStep, affinePrec, SIGNAL(valueChanged(double)), SLOT(OnX2Changed(double)));
 | 
						SetupAffineSpinner(table, this, 0, 1, m_PreX2Spin, spinHeight, affineMin, affineMax, affineStep, affinePrec, SIGNAL(valueChanged(double)), SLOT(OnX2Changed(double)));
 | 
				
			||||||
@ -26,7 +25,6 @@ void Fractorium::InitXformsAffineUI()
 | 
				
			|||||||
	SetupAffineSpinner(table, this, 1, 1, m_PreY2Spin, spinHeight, affineMin, affineMax, affineStep, affinePrec, SIGNAL(valueChanged(double)), SLOT(OnY2Changed(double)));
 | 
						SetupAffineSpinner(table, this, 1, 1, m_PreY2Spin, spinHeight, affineMin, affineMax, affineStep, affinePrec, SIGNAL(valueChanged(double)), SLOT(OnY2Changed(double)));
 | 
				
			||||||
	SetupAffineSpinner(table, this, 2, 0, m_PreO1Spin, spinHeight, affineMin, affineMax, affineStep, affinePrec, SIGNAL(valueChanged(double)), SLOT(OnO1Changed(double)));
 | 
						SetupAffineSpinner(table, this, 2, 0, m_PreO1Spin, spinHeight, affineMin, affineMax, affineStep, affinePrec, SIGNAL(valueChanged(double)), SLOT(OnO1Changed(double)));
 | 
				
			||||||
	SetupAffineSpinner(table, this, 2, 1, m_PreO2Spin, spinHeight, affineMin, affineMax, affineStep, affinePrec, SIGNAL(valueChanged(double)), SLOT(OnO2Changed(double)));
 | 
						SetupAffineSpinner(table, this, 2, 1, m_PreO2Spin, spinHeight, affineMin, affineMax, affineStep, affinePrec, SIGNAL(valueChanged(double)), SLOT(OnO2Changed(double)));
 | 
				
			||||||
 | 
					 | 
				
			||||||
	table = ui.PostAffineTable;
 | 
						table = ui.PostAffineTable;
 | 
				
			||||||
	table->verticalHeader()->setVisible(true);//The designer continually clobbers these values, so must manually set them here.
 | 
						table->verticalHeader()->setVisible(true);//The designer continually clobbers these values, so must manually set them here.
 | 
				
			||||||
	table->horizontalHeader()->setVisible(true);
 | 
						table->horizontalHeader()->setVisible(true);
 | 
				
			||||||
@ -34,10 +32,8 @@ void Fractorium::InitXformsAffineUI()
 | 
				
			|||||||
	table->horizontalHeader()->setSectionsClickable(true);
 | 
						table->horizontalHeader()->setSectionsClickable(true);
 | 
				
			||||||
	table->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
 | 
						table->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
 | 
				
			||||||
	table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
 | 
						table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	connect(table->verticalHeader(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(OnPostAffineRowDoubleClicked(int)), Qt::QueuedConnection);
 | 
						connect(table->verticalHeader(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(OnPostAffineRowDoubleClicked(int)), Qt::QueuedConnection);
 | 
				
			||||||
	connect(table->horizontalHeader(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(OnPostAffineColDoubleClicked(int)), Qt::QueuedConnection);
 | 
						connect(table->horizontalHeader(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(OnPostAffineColDoubleClicked(int)), Qt::QueuedConnection);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	//Post affine spinners.
 | 
						//Post affine spinners.
 | 
				
			||||||
	SetupAffineSpinner(table, this, 0, 0, m_PostX1Spin, spinHeight, affineMin, affineMax, affineStep, affinePrec, SIGNAL(valueChanged(double)), SLOT(OnX1Changed(double)));
 | 
						SetupAffineSpinner(table, this, 0, 0, m_PostX1Spin, spinHeight, affineMin, affineMax, affineStep, affinePrec, SIGNAL(valueChanged(double)), SLOT(OnX1Changed(double)));
 | 
				
			||||||
	SetupAffineSpinner(table, this, 0, 1, m_PostX2Spin, spinHeight, affineMin, affineMax, affineStep, affinePrec, SIGNAL(valueChanged(double)), SLOT(OnX2Changed(double)));
 | 
						SetupAffineSpinner(table, this, 0, 1, m_PostX2Spin, spinHeight, affineMin, affineMax, affineStep, affinePrec, SIGNAL(valueChanged(double)), SLOT(OnX2Changed(double)));
 | 
				
			||||||
@ -45,35 +41,27 @@ void Fractorium::InitXformsAffineUI()
 | 
				
			|||||||
	SetupAffineSpinner(table, this, 1, 1, m_PostY2Spin, spinHeight, affineMin, affineMax, affineStep, affinePrec, SIGNAL(valueChanged(double)), SLOT(OnY2Changed(double)));
 | 
						SetupAffineSpinner(table, this, 1, 1, m_PostY2Spin, spinHeight, affineMin, affineMax, affineStep, affinePrec, SIGNAL(valueChanged(double)), SLOT(OnY2Changed(double)));
 | 
				
			||||||
	SetupAffineSpinner(table, this, 2, 0, m_PostO1Spin, spinHeight, affineMin, affineMax, affineStep, affinePrec, SIGNAL(valueChanged(double)), SLOT(OnO1Changed(double)));
 | 
						SetupAffineSpinner(table, this, 2, 0, m_PostO1Spin, spinHeight, affineMin, affineMax, affineStep, affinePrec, SIGNAL(valueChanged(double)), SLOT(OnO1Changed(double)));
 | 
				
			||||||
	SetupAffineSpinner(table, this, 2, 1, m_PostO2Spin, spinHeight, affineMin, affineMax, affineStep, affinePrec, SIGNAL(valueChanged(double)), SLOT(OnO2Changed(double)));
 | 
						SetupAffineSpinner(table, this, 2, 1, m_PostO2Spin, spinHeight, affineMin, affineMax, affineStep, affinePrec, SIGNAL(valueChanged(double)), SLOT(OnO2Changed(double)));
 | 
				
			||||||
 | 
						auto preRotateVal  = new QDoubleValidator(ui.PreRotateCombo); preRotateVal->setLocale(QLocale::system());
 | 
				
			||||||
	QDoubleValidator* preRotateVal = new QDoubleValidator(ui.PreRotateCombo); preRotateVal->setLocale(QLocale::system());
 | 
						auto preMoveVal    = new QDoubleValidator(ui.PreMoveCombo);   preMoveVal->setLocale(QLocale::system());
 | 
				
			||||||
	QDoubleValidator* preMoveVal   = new QDoubleValidator(ui.PreMoveCombo);   preMoveVal->setLocale(QLocale::system());
 | 
						auto preScaleVal   = new QDoubleValidator(ui.PreScaleCombo);  preScaleVal->setLocale(QLocale::system());
 | 
				
			||||||
	QDoubleValidator* preScaleVal  = new QDoubleValidator(ui.PreScaleCombo);  preScaleVal->setLocale(QLocale::system());
 | 
						auto postRotateVal = new QDoubleValidator(ui.PostRotateCombo); postRotateVal->setLocale(QLocale::system());
 | 
				
			||||||
 | 
						auto postMoveVal   = new QDoubleValidator(ui.PostMoveCombo);   postMoveVal->setLocale(QLocale::system());
 | 
				
			||||||
	QDoubleValidator* postRotateVal = new QDoubleValidator(ui.PostRotateCombo); postRotateVal->setLocale(QLocale::system());
 | 
						auto postScaleVal  = new QDoubleValidator(ui.PostScaleCombo);  postScaleVal->setLocale(QLocale::system());
 | 
				
			||||||
	QDoubleValidator* postMoveVal   = new QDoubleValidator(ui.PostMoveCombo);   postMoveVal->setLocale(QLocale::system());
 | 
					 | 
				
			||||||
	QDoubleValidator* postScaleVal  = new QDoubleValidator(ui.PostScaleCombo);  postScaleVal->setLocale(QLocale::system());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ui.PreRotateCombo->setValidator(preRotateVal);
 | 
						ui.PreRotateCombo->setValidator(preRotateVal);
 | 
				
			||||||
	ui.PreMoveCombo->setValidator(preMoveVal);
 | 
						ui.PreMoveCombo->setValidator(preMoveVal);
 | 
				
			||||||
	ui.PreScaleCombo->setValidator(preScaleVal);
 | 
						ui.PreScaleCombo->setValidator(preScaleVal);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	ui.PostRotateCombo->setValidator(postRotateVal);
 | 
						ui.PostRotateCombo->setValidator(postRotateVal);
 | 
				
			||||||
	ui.PostMoveCombo->setValidator(postMoveVal);
 | 
						ui.PostMoveCombo->setValidator(postMoveVal);
 | 
				
			||||||
	ui.PostScaleCombo->setValidator(postScaleVal);
 | 
						ui.PostScaleCombo->setValidator(postScaleVal);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	QStringList moveList;
 | 
						QStringList moveList;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	moveList.append(ToString(0.5));
 | 
						moveList.append(ToString(0.5));
 | 
				
			||||||
	moveList.append(ToString(0.25));
 | 
						moveList.append(ToString(0.25));
 | 
				
			||||||
	moveList.append(ToString(0.1));
 | 
						moveList.append(ToString(0.1));
 | 
				
			||||||
	moveList.append(ToString(0.05));
 | 
						moveList.append(ToString(0.05));
 | 
				
			||||||
	moveList.append(ToString(0.025));
 | 
						moveList.append(ToString(0.025));
 | 
				
			||||||
	moveList.append(ToString(0.01));
 | 
						moveList.append(ToString(0.01));
 | 
				
			||||||
 | 
					 | 
				
			||||||
	ui.PreMoveCombo->addItems(moveList);
 | 
						ui.PreMoveCombo->addItems(moveList);
 | 
				
			||||||
	ui.PostMoveCombo->addItems(moveList);
 | 
						ui.PostMoveCombo->addItems(moveList);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	connect(ui.PreFlipHorizontalButton,    SIGNAL(clicked(bool)),     this, SLOT(OnFlipHorizontalButtonClicked(bool)),			  Qt::QueuedConnection);
 | 
						connect(ui.PreFlipHorizontalButton,    SIGNAL(clicked(bool)),     this, SLOT(OnFlipHorizontalButtonClicked(bool)),			  Qt::QueuedConnection);
 | 
				
			||||||
	connect(ui.PreFlipVerticalButton,      SIGNAL(clicked(bool)),     this, SLOT(OnFlipVerticalButtonClicked(bool)),			  Qt::QueuedConnection);
 | 
						connect(ui.PreFlipVerticalButton,      SIGNAL(clicked(bool)),     this, SLOT(OnFlipVerticalButtonClicked(bool)),			  Qt::QueuedConnection);
 | 
				
			||||||
	connect(ui.PreRotate90CButton,         SIGNAL(clicked(bool)),     this, SLOT(OnRotate90CButtonClicked(bool)),				  Qt::QueuedConnection);
 | 
						connect(ui.PreRotate90CButton,         SIGNAL(clicked(bool)),     this, SLOT(OnRotate90CButtonClicked(bool)),				  Qt::QueuedConnection);
 | 
				
			||||||
@ -87,7 +75,6 @@ void Fractorium::InitXformsAffineUI()
 | 
				
			|||||||
	connect(ui.PreScaleDownButton,         SIGNAL(clicked(bool)),     this, SLOT(OnScaleDownButtonClicked(bool)),				  Qt::QueuedConnection);
 | 
						connect(ui.PreScaleDownButton,         SIGNAL(clicked(bool)),     this, SLOT(OnScaleDownButtonClicked(bool)),				  Qt::QueuedConnection);
 | 
				
			||||||
	connect(ui.PreScaleUpButton,           SIGNAL(clicked(bool)),     this, SLOT(OnScaleUpButtonClicked(bool)),					  Qt::QueuedConnection);
 | 
						connect(ui.PreScaleUpButton,           SIGNAL(clicked(bool)),     this, SLOT(OnScaleUpButtonClicked(bool)),					  Qt::QueuedConnection);
 | 
				
			||||||
	connect(ui.PreResetButton,             SIGNAL(clicked(bool)),     this, SLOT(OnResetAffineButtonClicked(bool)),				  Qt::QueuedConnection);
 | 
						connect(ui.PreResetButton,             SIGNAL(clicked(bool)),     this, SLOT(OnResetAffineButtonClicked(bool)),				  Qt::QueuedConnection);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	connect(ui.PostFlipHorizontalButton,   SIGNAL(clicked(bool)),     this, SLOT(OnFlipHorizontalButtonClicked(bool)),			  Qt::QueuedConnection);
 | 
						connect(ui.PostFlipHorizontalButton,   SIGNAL(clicked(bool)),     this, SLOT(OnFlipHorizontalButtonClicked(bool)),			  Qt::QueuedConnection);
 | 
				
			||||||
	connect(ui.PostFlipVerticalButton,     SIGNAL(clicked(bool)),     this, SLOT(OnFlipVerticalButtonClicked(bool)),			  Qt::QueuedConnection);
 | 
						connect(ui.PostFlipVerticalButton,     SIGNAL(clicked(bool)),     this, SLOT(OnFlipVerticalButtonClicked(bool)),			  Qt::QueuedConnection);
 | 
				
			||||||
	connect(ui.PostRotate90CcButton,       SIGNAL(clicked(bool)),     this, SLOT(OnRotate90CcButtonClicked(bool)),				  Qt::QueuedConnection);
 | 
						connect(ui.PostRotate90CcButton,       SIGNAL(clicked(bool)),     this, SLOT(OnRotate90CcButtonClicked(bool)),				  Qt::QueuedConnection);
 | 
				
			||||||
@ -101,17 +88,13 @@ void Fractorium::InitXformsAffineUI()
 | 
				
			|||||||
	connect(ui.PostScaleDownButton,        SIGNAL(clicked(bool)),     this, SLOT(OnScaleDownButtonClicked(bool)),				  Qt::QueuedConnection);
 | 
						connect(ui.PostScaleDownButton,        SIGNAL(clicked(bool)),     this, SLOT(OnScaleDownButtonClicked(bool)),				  Qt::QueuedConnection);
 | 
				
			||||||
	connect(ui.PostScaleUpButton,          SIGNAL(clicked(bool)),     this, SLOT(OnScaleUpButtonClicked(bool)),					  Qt::QueuedConnection);
 | 
						connect(ui.PostScaleUpButton,          SIGNAL(clicked(bool)),     this, SLOT(OnScaleUpButtonClicked(bool)),					  Qt::QueuedConnection);
 | 
				
			||||||
	connect(ui.PostResetButton,            SIGNAL(clicked(bool)),     this, SLOT(OnResetAffineButtonClicked(bool)),				  Qt::QueuedConnection);
 | 
						connect(ui.PostResetButton,            SIGNAL(clicked(bool)),     this, SLOT(OnResetAffineButtonClicked(bool)),				  Qt::QueuedConnection);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	connect(ui.PreAffineGroupBox,		   SIGNAL(toggled(bool)),     this, SLOT(OnAffineGroupBoxToggled(bool)),				  Qt::QueuedConnection);
 | 
						connect(ui.PreAffineGroupBox,		   SIGNAL(toggled(bool)),     this, SLOT(OnAffineGroupBoxToggled(bool)),				  Qt::QueuedConnection);
 | 
				
			||||||
	connect(ui.PostAffineGroupBox,		   SIGNAL(toggled(bool)),     this, SLOT(OnAffineGroupBoxToggled(bool)),				  Qt::QueuedConnection);
 | 
						connect(ui.PostAffineGroupBox,		   SIGNAL(toggled(bool)),     this, SLOT(OnAffineGroupBoxToggled(bool)),				  Qt::QueuedConnection);
 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	connect(ui.ShowPreAffineAllRadio,      SIGNAL(toggled(bool)),     this, SLOT(OnAffineDrawAllCurrentRadioButtonToggled(bool)), Qt::QueuedConnection);
 | 
						connect(ui.ShowPreAffineAllRadio,      SIGNAL(toggled(bool)),     this, SLOT(OnAffineDrawAllCurrentRadioButtonToggled(bool)), Qt::QueuedConnection);
 | 
				
			||||||
	connect(ui.ShowPreAffineCurrentRadio,  SIGNAL(toggled(bool)),     this, SLOT(OnAffineDrawAllCurrentRadioButtonToggled(bool)), Qt::QueuedConnection);
 | 
						connect(ui.ShowPreAffineCurrentRadio,  SIGNAL(toggled(bool)),     this, SLOT(OnAffineDrawAllCurrentRadioButtonToggled(bool)), Qt::QueuedConnection);
 | 
				
			||||||
	connect(ui.ShowPostAffineAllRadio,     SIGNAL(toggled(bool)),     this, SLOT(OnAffineDrawAllCurrentRadioButtonToggled(bool)), Qt::QueuedConnection);
 | 
						connect(ui.ShowPostAffineAllRadio,     SIGNAL(toggled(bool)),     this, SLOT(OnAffineDrawAllCurrentRadioButtonToggled(bool)), Qt::QueuedConnection);
 | 
				
			||||||
	connect(ui.ShowPostAffineCurrentRadio, SIGNAL(toggled(bool)),     this, SLOT(OnAffineDrawAllCurrentRadioButtonToggled(bool)), Qt::QueuedConnection);
 | 
						connect(ui.ShowPostAffineCurrentRadio, SIGNAL(toggled(bool)),     this, SLOT(OnAffineDrawAllCurrentRadioButtonToggled(bool)), Qt::QueuedConnection);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	connect(ui.PolarAffineCheckBox,        SIGNAL(stateChanged(int)), this, SLOT(OnPolarAffineCheckBoxStateChanged(int)),		  Qt::QueuedConnection);
 | 
						connect(ui.PolarAffineCheckBox,        SIGNAL(stateChanged(int)), this, SLOT(OnPolarAffineCheckBoxStateChanged(int)),		  Qt::QueuedConnection);
 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef WIN32
 | 
					#ifndef WIN32
 | 
				
			||||||
	//For some reason linux makes these 24x24, even though the designer explicitly says 16x16.
 | 
						//For some reason linux makes these 24x24, even though the designer explicitly says 16x16.
 | 
				
			||||||
	//Also, in order to get 4 pixels of spacing between elements in the grid layout, 0 must be specified.
 | 
						//Also, in order to get 4 pixels of spacing between elements in the grid layout, 0 must be specified.
 | 
				
			||||||
@ -130,7 +113,6 @@ void Fractorium::InitXformsAffineUI()
 | 
				
			|||||||
	ui.PreResetButton->setIconSize(QSize(16, 16));
 | 
						ui.PreResetButton->setIconSize(QSize(16, 16));
 | 
				
			||||||
	ui.PreAffineGridLayout->setHorizontalSpacing(0);
 | 
						ui.PreAffineGridLayout->setHorizontalSpacing(0);
 | 
				
			||||||
	ui.PreAffineGridLayout->setVerticalSpacing(0);
 | 
						ui.PreAffineGridLayout->setVerticalSpacing(0);
 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	ui.PostFlipHorizontalButton->setIconSize(QSize(16, 16));
 | 
						ui.PostFlipHorizontalButton->setIconSize(QSize(16, 16));
 | 
				
			||||||
	ui.PostFlipVerticalButton->setIconSize(QSize(16, 16));
 | 
						ui.PostFlipVerticalButton->setIconSize(QSize(16, 16));
 | 
				
			||||||
	ui.PostRotate90CButton->setIconSize(QSize(16, 16));
 | 
						ui.PostRotate90CButton->setIconSize(QSize(16, 16));
 | 
				
			||||||
@ -146,13 +128,11 @@ void Fractorium::InitXformsAffineUI()
 | 
				
			|||||||
	ui.PostResetButton->setIconSize(QSize(16, 16));
 | 
						ui.PostResetButton->setIconSize(QSize(16, 16));
 | 
				
			||||||
	ui.PostAffineGridLayout->setHorizontalSpacing(0);
 | 
						ui.PostAffineGridLayout->setHorizontalSpacing(0);
 | 
				
			||||||
	ui.PostAffineGridLayout->setVerticalSpacing(0);
 | 
						ui.PostAffineGridLayout->setVerticalSpacing(0);
 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	//Further, the size of the dock widget won't be properly adjusted until the xforms tab is shown.
 | 
						//Further, the size of the dock widget won't be properly adjusted until the xforms tab is shown.
 | 
				
			||||||
	//So show it here and it will be switched back in Fractorium's constructor.
 | 
						//So show it here and it will be switched back in Fractorium's constructor.
 | 
				
			||||||
	//ui.ParamsTabWidget->setCurrentIndex(2);
 | 
						//ui.ParamsTabWidget->setCurrentIndex(2);
 | 
				
			||||||
	//ui.DockWidget->update();
 | 
						//ui.DockWidget->update();
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	//Placing pointers to the spin boxes in arrays makes them easier to access in various places.
 | 
						//Placing pointers to the spin boxes in arrays makes them easier to access in various places.
 | 
				
			||||||
	m_PreSpins[0] = m_PreX1Spin;//A
 | 
						m_PreSpins[0] = m_PreX1Spin;//A
 | 
				
			||||||
	m_PreSpins[1] = m_PreY1Spin;//B
 | 
						m_PreSpins[1] = m_PreY1Spin;//B
 | 
				
			||||||
@ -160,20 +140,58 @@ void Fractorium::InitXformsAffineUI()
 | 
				
			|||||||
	m_PreSpins[3] = m_PreX2Spin;//D
 | 
						m_PreSpins[3] = m_PreX2Spin;//D
 | 
				
			||||||
	m_PreSpins[4] = m_PreY2Spin;//E
 | 
						m_PreSpins[4] = m_PreY2Spin;//E
 | 
				
			||||||
	m_PreSpins[5] = m_PreO2Spin;//F
 | 
						m_PreSpins[5] = m_PreO2Spin;//F
 | 
				
			||||||
 | 
					 | 
				
			||||||
	m_PostSpins[0] = m_PostX1Spin;
 | 
						m_PostSpins[0] = m_PostX1Spin;
 | 
				
			||||||
	m_PostSpins[1] = m_PostY1Spin;
 | 
						m_PostSpins[1] = m_PostY1Spin;
 | 
				
			||||||
	m_PostSpins[2] = m_PostO1Spin;
 | 
						m_PostSpins[2] = m_PostO1Spin;
 | 
				
			||||||
	m_PostSpins[3] = m_PostX2Spin;
 | 
						m_PostSpins[3] = m_PostX2Spin;
 | 
				
			||||||
	m_PostSpins[4] = m_PostY2Spin;
 | 
						m_PostSpins[4] = m_PostY2Spin;
 | 
				
			||||||
	m_PostSpins[5] = m_PostO2Spin;
 | 
						m_PostSpins[5] = m_PostO2Spin;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	ui.PreAffineGroupBox->setChecked(false);//Flip both once to force enabling/disabling the disabling of the group boxes and the corner buttons.
 | 
						ui.PreAffineGroupBox->setChecked(false);//Flip both once to force enabling/disabling the disabling of the group boxes and the corner buttons.
 | 
				
			||||||
	ui.PreAffineGroupBox->setChecked(true);//Pre affine enabled.
 | 
						ui.PreAffineGroupBox->setChecked(true);//Pre affine enabled.
 | 
				
			||||||
	ui.PostAffineGroupBox->setChecked(true);
 | 
						ui.PostAffineGroupBox->setChecked(true);
 | 
				
			||||||
	ui.PostAffineGroupBox->setChecked(false);//Post affine disabled.
 | 
						ui.PostAffineGroupBox->setChecked(false);//Post affine disabled.
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Toggle whether to lock the visual scale of the affine spinners.
 | 
				
			||||||
 | 
					/// Called when the user checks LockAffineCheckBox.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					/// <param name="state">True if checked, else false.</param>
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					void FractoriumEmberController<T>::LockAffineScaleCheckBoxStateChanged(int state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						m_LockedScale = m_Ember.m_PixelsPerUnit;
 | 
				
			||||||
 | 
						m_Fractorium->ui.GLDisplay->update();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Fractorium::OnLockAffineScaleCheckBoxStateChanged(int state) { m_Controller->LockAffineScaleCheckBoxStateChanged(state); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Return the value needed to multiply the current scale by to get back to the locked scale.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					/// <returns>The scale value</returns>
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					T FractoriumEmberController<T>::AffineScaleCurrentToLocked()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (m_Fractorium->ui.LockAffineCheckBox->isChecked())
 | 
				
			||||||
 | 
							return LockedScale() / m_Ember.m_PixelsPerUnit;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Return the value needed to multiply the locked scale by to get to the current scale.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					/// <returns>The scale value</returns>
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					T FractoriumEmberController<T>::AffineScaleLockedToCurrent()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (m_Fractorium->ui.LockAffineCheckBox->isChecked())
 | 
				
			||||||
 | 
							return m_Ember.m_PixelsPerUnit / LockedScale();
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
/// Toggle all pre affine values in one row for the selected xforms.
 | 
					/// Toggle all pre affine values in one row for the selected xforms.
 | 
				
			||||||
/// Resets the rendering process.
 | 
					/// Resets the rendering process.
 | 
				
			||||||
@ -226,7 +244,7 @@ void FractoriumEmberController<T>::AffineSetHelper(double d, int index, bool pre
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	UpdateXform([&] (Xform<T>* xform)
 | 
						UpdateXform([&] (Xform<T>* xform)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Affine2D<T>* affine = pre ? &xform->m_Affine : &xform->m_Post;
 | 
							auto affine = pre ? &xform->m_Affine : &xform->m_Post;
 | 
				
			||||||
		DoubleSpinBox** spinners = pre ? m_Fractorium->m_PreSpins : m_Fractorium->m_PostSpins;
 | 
							DoubleSpinBox** spinners = pre ? m_Fractorium->m_PreSpins : m_Fractorium->m_PostSpins;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (m_Fractorium->ui.PolarAffineCheckBox->isChecked())
 | 
							if (m_Fractorium->ui.PolarAffineCheckBox->isChecked())
 | 
				
			||||||
@ -238,11 +256,13 @@ void FractoriumEmberController<T>::AffineSetHelper(double d, int index, bool pre
 | 
				
			|||||||
					affine->A(cos(spinners[0]->value() * DEG_2_RAD) * spinners[3]->value());
 | 
										affine->A(cos(spinners[0]->value() * DEG_2_RAD) * spinners[3]->value());
 | 
				
			||||||
					affine->D(sin(spinners[0]->value() * DEG_2_RAD) * spinners[3]->value());
 | 
										affine->D(sin(spinners[0]->value() * DEG_2_RAD) * spinners[3]->value());
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				case 1:
 | 
									case 1:
 | 
				
			||||||
				case 4:
 | 
									case 4:
 | 
				
			||||||
					affine->B(cos(spinners[1]->value() * DEG_2_RAD) * spinners[4]->value());
 | 
										affine->B(cos(spinners[1]->value() * DEG_2_RAD) * spinners[4]->value());
 | 
				
			||||||
					affine->E(sin(spinners[1]->value() * DEG_2_RAD) * spinners[4]->value());
 | 
										affine->E(sin(spinners[1]->value() * DEG_2_RAD) * spinners[4]->value());
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				case 2:
 | 
									case 2:
 | 
				
			||||||
				case 5:
 | 
									case 5:
 | 
				
			||||||
				default:
 | 
									default:
 | 
				
			||||||
@ -258,18 +278,23 @@ void FractoriumEmberController<T>::AffineSetHelper(double d, int index, bool pre
 | 
				
			|||||||
				case 0:
 | 
									case 0:
 | 
				
			||||||
					affine->A(d);
 | 
										affine->A(d);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				case 1:
 | 
									case 1:
 | 
				
			||||||
					affine->B(d);
 | 
										affine->B(d);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				case 2:
 | 
									case 2:
 | 
				
			||||||
					affine->C(d);
 | 
										affine->C(d);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				case 3:
 | 
									case 3:
 | 
				
			||||||
					affine->D(d);
 | 
										affine->D(d);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				case 4:
 | 
									case 4:
 | 
				
			||||||
					affine->E(d);
 | 
										affine->E(d);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				case 5:
 | 
									case 5:
 | 
				
			||||||
					affine->F(d);
 | 
										affine->F(d);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
@ -301,7 +326,7 @@ void FractoriumEmberController<T>::FlipXforms(bool horizontal, bool vertical, bo
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	UpdateXform([&] (Xform<T>* xform)
 | 
						UpdateXform([&] (Xform<T>* xform)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Affine2D<T>* affine = pre ? &xform->m_Affine : &xform->m_Post;
 | 
							auto affine = pre ? &xform->m_Affine : &xform->m_Post;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (horizontal)
 | 
							if (horizontal)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@ -320,9 +345,7 @@ void FractoriumEmberController<T>::FlipXforms(bool horizontal, bool vertical, bo
 | 
				
			|||||||
			if (!m_Fractorium->LocalPivot())
 | 
								if (!m_Fractorium->LocalPivot())
 | 
				
			||||||
				affine->F(-affine->F());
 | 
									affine->F(-affine->F());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	}, eXformUpdate::UPDATE_SELECTED);
 | 
						}, eXformUpdate::UPDATE_SELECTED);
 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	FillAffineWithXform(CurrentXform(), pre);
 | 
						FillAffineWithXform(CurrentXform(), pre);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -340,11 +363,9 @@ void FractoriumEmberController<T>::RotateXformsByAngle(double angle, bool pre)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	UpdateXform([&] (Xform<T>* xform)
 | 
						UpdateXform([&] (Xform<T>* xform)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Affine2D<T>* affine = pre ? &xform->m_Affine : &xform->m_Post;
 | 
							auto affine = pre ? &xform->m_Affine : &xform->m_Post;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		affine->Rotate(angle);
 | 
							affine->Rotate(angle);
 | 
				
			||||||
	}, eXformUpdate::UPDATE_SELECTED);
 | 
						}, eXformUpdate::UPDATE_SELECTED);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	FillAffineWithXform(CurrentXform(), pre);
 | 
						FillAffineWithXform(CurrentXform(), pre);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -367,7 +388,7 @@ void Fractorium::OnRotateCButtonClicked(bool checked)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	bool ok;
 | 
						bool ok;
 | 
				
			||||||
	bool pre = sender() == ui.PreRotateCButton;
 | 
						bool pre = sender() == ui.PreRotateCButton;
 | 
				
			||||||
	QComboBox* combo = pre ? ui.PreRotateCombo : ui.PostRotateCombo;
 | 
						auto combo = pre ? ui.PreRotateCombo : ui.PostRotateCombo;
 | 
				
			||||||
	double d = ToDouble(combo->currentText(), &ok);
 | 
						double d = ToDouble(combo->currentText(), &ok);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ok)
 | 
						if (ok)
 | 
				
			||||||
@ -384,7 +405,7 @@ void Fractorium::OnRotateCcButtonClicked(bool checked)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	bool ok;
 | 
						bool ok;
 | 
				
			||||||
	bool pre = sender() == ui.PreRotateCcButton;
 | 
						bool pre = sender() == ui.PreRotateCcButton;
 | 
				
			||||||
	QComboBox* combo = pre ? ui.PreRotateCombo : ui.PostRotateCombo;
 | 
						auto combo = pre ? ui.PreRotateCombo : ui.PostRotateCombo;
 | 
				
			||||||
	double d = ToDouble(combo->currentText(), &ok);
 | 
						double d = ToDouble(combo->currentText(), &ok);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ok)
 | 
						if (ok)
 | 
				
			||||||
@ -403,12 +424,10 @@ void FractoriumEmberController<T>::MoveXforms(double x, double y, bool pre)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	UpdateXform([&] (Xform<T>* xform)
 | 
						UpdateXform([&] (Xform<T>* xform)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Affine2D<T>* affine = pre ? &xform->m_Affine : &xform->m_Post;
 | 
							auto* affine = pre ? &xform->m_Affine : &xform->m_Post;
 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		affine->C(affine->C() + x);
 | 
							affine->C(affine->C() + x);
 | 
				
			||||||
		affine->F(affine->F() + y);
 | 
							affine->F(affine->F() + y);
 | 
				
			||||||
	}, eXformUpdate::UPDATE_SELECTED);
 | 
						}, eXformUpdate::UPDATE_SELECTED);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	FillAffineWithXform(CurrentXform(), pre);
 | 
						FillAffineWithXform(CurrentXform(), pre);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -422,7 +441,7 @@ void Fractorium::OnMoveUpButtonClicked(bool checked)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	bool ok;
 | 
						bool ok;
 | 
				
			||||||
	bool pre = sender() == ui.PreMoveUpButton;
 | 
						bool pre = sender() == ui.PreMoveUpButton;
 | 
				
			||||||
	QComboBox* combo = pre ? ui.PreMoveCombo : ui.PostMoveCombo;
 | 
						auto combo = pre ? ui.PreMoveCombo : ui.PostMoveCombo;
 | 
				
			||||||
	double d = ToDouble(combo->currentText(), &ok);
 | 
						double d = ToDouble(combo->currentText(), &ok);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ok)
 | 
						if (ok)
 | 
				
			||||||
@ -439,7 +458,7 @@ void Fractorium::OnMoveDownButtonClicked(bool checked)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	bool ok;
 | 
						bool ok;
 | 
				
			||||||
	bool pre = sender() == ui.PreMoveDownButton;
 | 
						bool pre = sender() == ui.PreMoveDownButton;
 | 
				
			||||||
	QComboBox* combo = pre ? ui.PreMoveCombo : ui.PostMoveCombo;
 | 
						auto combo = pre ? ui.PreMoveCombo : ui.PostMoveCombo;
 | 
				
			||||||
	double d = ToDouble(combo->currentText(), &ok);
 | 
						double d = ToDouble(combo->currentText(), &ok);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ok)
 | 
						if (ok)
 | 
				
			||||||
@ -456,7 +475,7 @@ void Fractorium::OnMoveLeftButtonClicked(bool checked)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	bool ok;
 | 
						bool ok;
 | 
				
			||||||
	bool pre = sender() == ui.PreMoveLeftButton;
 | 
						bool pre = sender() == ui.PreMoveLeftButton;
 | 
				
			||||||
	QComboBox* combo = pre ? ui.PreMoveCombo : ui.PostMoveCombo;
 | 
						auto combo = pre ? ui.PreMoveCombo : ui.PostMoveCombo;
 | 
				
			||||||
	double d = ToDouble(combo->currentText(), &ok);
 | 
						double d = ToDouble(combo->currentText(), &ok);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ok)
 | 
						if (ok)
 | 
				
			||||||
@ -473,7 +492,7 @@ void Fractorium::OnMoveRightButtonClicked(bool checked)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	bool ok;
 | 
						bool ok;
 | 
				
			||||||
	bool pre = sender() == ui.PreMoveRightButton;
 | 
						bool pre = sender() == ui.PreMoveRightButton;
 | 
				
			||||||
	QComboBox* combo = pre ? ui.PreMoveCombo : ui.PostMoveCombo;
 | 
						auto combo = pre ? ui.PreMoveCombo : ui.PostMoveCombo;
 | 
				
			||||||
	double d = ToDouble(combo->currentText(), &ok);
 | 
						double d = ToDouble(combo->currentText(), &ok);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ok)
 | 
						if (ok)
 | 
				
			||||||
@ -491,14 +510,12 @@ void FractoriumEmberController<T>::ScaleXforms(double scale, bool pre)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	UpdateXform([&] (Xform<T>* xform)
 | 
						UpdateXform([&] (Xform<T>* xform)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Affine2D<T>* affine = pre ? &xform->m_Affine : &xform->m_Post;
 | 
							auto affine = pre ? &xform->m_Affine : &xform->m_Post;
 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		affine->A(affine->A() * scale);
 | 
							affine->A(affine->A() * scale);
 | 
				
			||||||
		affine->B(affine->B() * scale);
 | 
							affine->B(affine->B() * scale);
 | 
				
			||||||
		affine->D(affine->D() * scale);
 | 
							affine->D(affine->D() * scale);
 | 
				
			||||||
		affine->E(affine->E() * scale);
 | 
							affine->E(affine->E() * scale);
 | 
				
			||||||
	}, eXformUpdate::UPDATE_SELECTED);
 | 
						}, eXformUpdate::UPDATE_SELECTED);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	FillAffineWithXform(CurrentXform(), pre);
 | 
						FillAffineWithXform(CurrentXform(), pre);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -512,7 +529,7 @@ void Fractorium::OnScaleDownButtonClicked(bool checked)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	bool ok;
 | 
						bool ok;
 | 
				
			||||||
	bool pre = sender() == ui.PreScaleDownButton;
 | 
						bool pre = sender() == ui.PreScaleDownButton;
 | 
				
			||||||
	QComboBox* combo = pre ? ui.PreScaleCombo : ui.PostScaleCombo;
 | 
						auto combo = pre ? ui.PreScaleCombo : ui.PostScaleCombo;
 | 
				
			||||||
	double d = ToDouble(combo->currentText(), &ok);
 | 
						double d = ToDouble(combo->currentText(), &ok);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ok)
 | 
						if (ok)
 | 
				
			||||||
@ -529,7 +546,7 @@ void Fractorium::OnScaleUpButtonClicked(bool checked)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	bool ok;
 | 
						bool ok;
 | 
				
			||||||
	bool pre = sender() == ui.PreScaleUpButton;
 | 
						bool pre = sender() == ui.PreScaleUpButton;
 | 
				
			||||||
	QComboBox* combo = pre ? ui.PreScaleCombo : ui.PostScaleCombo;
 | 
						auto combo = pre ? ui.PreScaleCombo : ui.PostScaleCombo;
 | 
				
			||||||
	double d = ToDouble(combo->currentText(), &ok);
 | 
						double d = ToDouble(combo->currentText(), &ok);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ok)
 | 
						if (ok)
 | 
				
			||||||
@ -546,11 +563,9 @@ void FractoriumEmberController<T>::ResetXformsAffine(bool pre)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	UpdateXform([&] (Xform<T>* xform)
 | 
						UpdateXform([&] (Xform<T>* xform)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Affine2D<T>* affine = pre ? &xform->m_Affine : &xform->m_Post;
 | 
							auto affine = pre ? &xform->m_Affine : &xform->m_Post;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		affine->MakeID();
 | 
							affine->MakeID();
 | 
				
			||||||
	}, eXformUpdate::UPDATE_SELECTED);
 | 
						}, eXformUpdate::UPDATE_SELECTED);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	FillAffineWithXform(CurrentXform(), pre);
 | 
						FillAffineWithXform(CurrentXform(), pre);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -142,6 +142,7 @@ private:
 | 
				
			|||||||
	m4T m_Projection;
 | 
						m4T m_Projection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Affine2D<T> m_DragSrcTransform;
 | 
						Affine2D<T> m_DragSrcTransform;
 | 
				
			||||||
 | 
						vector<Affine2D<T>> m_DragSrcTransforms;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Xform<T>* m_HoverXform;
 | 
						Xform<T>* m_HoverXform;
 | 
				
			||||||
	Xform<T>* m_SelectedXform;
 | 
						Xform<T>* m_SelectedXform;
 | 
				
			||||||
 | 
				
			|||||||
@ -2,8 +2,6 @@
 | 
				
			|||||||
#include "GLWidget.h"
 | 
					#include "GLWidget.h"
 | 
				
			||||||
#include "Fractorium.h"
 | 
					#include "Fractorium.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//#define OLDDRAG 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// <summary>
 | 
					/// <summary>
 | 
				
			||||||
/// Constructor which passes parent widget to the base and initializes OpenGL profile.
 | 
					/// Constructor which passes parent widget to the base and initializes OpenGL profile.
 | 
				
			||||||
/// This will need to change in the future to implement all drawing as shader programs.
 | 
					/// This will need to change in the future to implement all drawing as shader programs.
 | 
				
			||||||
@ -142,7 +140,7 @@ void GLEmberControllerBase::ClearControl() { m_DragModifier &= ~et(eDragModifier
 | 
				
			|||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
void GLEmberController<T>::ClearWindow()
 | 
					void GLEmberController<T>::ClearWindow()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
 | 
						auto ember = m_FractoriumEmberController->CurrentEmber();
 | 
				
			||||||
	m_GL->makeCurrent();
 | 
						m_GL->makeCurrent();
 | 
				
			||||||
	m_GL->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 | 
						m_GL->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 | 
				
			||||||
	m_GL->glClearColor(ember->m_Background.r, ember->m_Background.g, ember->m_Background.b, 1.0);
 | 
						m_GL->glClearColor(ember->m_Background.r, ember->m_Background.g, ember->m_Background.b, 1.0);
 | 
				
			||||||
@ -211,10 +209,10 @@ void GLWidget::initializeGL()
 | 
				
			|||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
void GLWidget::paintGL()
 | 
					void GLWidget::paintGL()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	FractoriumEmberControllerBase* controller = m_Fractorium->m_Controller.get();
 | 
						auto controller = m_Fractorium->m_Controller.get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//Ensure there is a renderer and that it's supposed to be drawing, signified by the running timer.
 | 
						//Ensure there is a renderer and that it's supposed to be drawing, signified by the running timer.
 | 
				
			||||||
	if (controller && controller->Renderer() && controller->RenderTimerRunning())
 | 
						if (controller && controller->Renderer())
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		RendererBase* renderer = controller->Renderer();
 | 
							RendererBase* renderer = controller->Renderer();
 | 
				
			||||||
		m_Drawing = true;
 | 
							m_Drawing = true;
 | 
				
			||||||
@ -256,8 +254,8 @@ void GLWidget::paintGL()
 | 
				
			|||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
void GLEmberController<T>::DrawImage()
 | 
					void GLEmberController<T>::DrawImage()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	RendererBase* renderer = m_FractoriumEmberController->Renderer();
 | 
						auto renderer = m_FractoriumEmberController->Renderer();
 | 
				
			||||||
	Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
 | 
						auto ember = m_FractoriumEmberController->CurrentEmber();
 | 
				
			||||||
	m_GL->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 | 
						m_GL->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 | 
				
			||||||
	m_GL->glClearColor(ember->m_Background.r, ember->m_Background.g, ember->m_Background.b, 1.0);
 | 
						m_GL->glClearColor(ember->m_Background.r, ember->m_Background.g, ember->m_Background.b, 1.0);
 | 
				
			||||||
	m_GL->glDisable(GL_DEPTH_TEST);
 | 
						m_GL->glDisable(GL_DEPTH_TEST);
 | 
				
			||||||
@ -286,14 +284,14 @@ template <typename T>
 | 
				
			|||||||
void GLEmberController<T>::DrawAffines(bool pre, bool post)
 | 
					void GLEmberController<T>::DrawAffines(bool pre, bool post)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	QueryVMP();//Resolves to float or double specialization function depending on T.
 | 
						QueryVMP();//Resolves to float or double specialization function depending on T.
 | 
				
			||||||
	Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
 | 
						auto ember = m_FractoriumEmberController->CurrentEmber();
 | 
				
			||||||
	bool dragging = m_DragState == eDragState::DragDragging;
 | 
						bool dragging = m_DragState == eDragState::DragDragging;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//Draw grid if control key is pressed.
 | 
						//Draw grid if control key is pressed.
 | 
				
			||||||
	if (m_GL->hasFocus() && GetControl())
 | 
						if (m_GL->hasFocus() && GetControl())
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		m_GL->glLineWidth(1.0f);
 | 
							m_GL->glLineWidth(1.0f);
 | 
				
			||||||
		m_GL->DrawGrid();
 | 
							m_GL->DrawGrid(m_FractoriumEmberController->AffineScaleLockedToCurrent());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//When dragging, only draw the selected xform's affine and hide all others.
 | 
						//When dragging, only draw the selected xform's affine and hide all others.
 | 
				
			||||||
@ -308,7 +306,7 @@ void GLEmberController<T>::DrawAffines(bool pre, bool post)
 | 
				
			|||||||
		{
 | 
							{
 | 
				
			||||||
			for (size_t i = 0; i < ember->TotalXformCount(); i++)
 | 
								for (size_t i = 0; i < ember->TotalXformCount(); i++)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				Xform<T>* xform = ember->GetTotalXform(i);
 | 
									auto xform = ember->GetTotalXform(i);
 | 
				
			||||||
				bool selected = dragging ? (m_SelectedXform == xform) : (m_HoverXform == xform);
 | 
									bool selected = dragging ? (m_SelectedXform == xform) : (m_HoverXform == xform);
 | 
				
			||||||
				DrawAffine(xform, true, selected);
 | 
									DrawAffine(xform, true, selected);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -322,7 +320,7 @@ void GLEmberController<T>::DrawAffines(bool pre, bool post)
 | 
				
			|||||||
		{
 | 
							{
 | 
				
			||||||
			for (size_t i = 0; i < ember->TotalXformCount(); i++)
 | 
								for (size_t i = 0; i < ember->TotalXformCount(); i++)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				Xform<T>* xform = ember->GetTotalXform(i);
 | 
									auto xform = ember->GetTotalXform(i);
 | 
				
			||||||
				bool selected = dragging ? (m_SelectedXform == xform) : (m_HoverXform == xform);
 | 
									bool selected = dragging ? (m_SelectedXform == xform) : (m_HoverXform == xform);
 | 
				
			||||||
				DrawAffine(xform, false, selected);
 | 
									DrawAffine(xform, false, selected);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -359,27 +357,12 @@ void GLEmberController<T>::DrawAffines(bool pre, bool post)
 | 
				
			|||||||
/// <param name="e">The event</param>
 | 
					/// <param name="e">The event</param>
 | 
				
			||||||
bool GLEmberControllerBase::KeyPress_(QKeyEvent* e)
 | 
					bool GLEmberControllerBase::KeyPress_(QKeyEvent* e)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef OLDDRAG
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (e->key() == Qt::Key_Shift)
 | 
					 | 
				
			||||||
		SetShift();
 | 
					 | 
				
			||||||
	else if (e->key() == Qt::Key_Control || e->key() == Qt::Key_C)
 | 
					 | 
				
			||||||
		SetControl();
 | 
					 | 
				
			||||||
	else if (e->key() == Qt::Key_Alt || e->key() == Qt::Key_A)
 | 
					 | 
				
			||||||
		SetAlt();
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return true;
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (e->key() == Qt::Key_Control)
 | 
						if (e->key() == Qt::Key_Control)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		SetControl();
 | 
							SetControl();
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -401,27 +384,12 @@ void GLWidget::keyPressEvent(QKeyEvent* e)
 | 
				
			|||||||
/// <param name="e">The event</param>
 | 
					/// <param name="e">The event</param>
 | 
				
			||||||
bool GLEmberControllerBase::KeyRelease_(QKeyEvent* e)
 | 
					bool GLEmberControllerBase::KeyRelease_(QKeyEvent* e)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef OLDDRAG
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (e->key() == Qt::Key_Shift)
 | 
					 | 
				
			||||||
		ClearShift();
 | 
					 | 
				
			||||||
	else if (e->key() == Qt::Key_Control || e->key() == Qt::Key_C)
 | 
					 | 
				
			||||||
		ClearControl();
 | 
					 | 
				
			||||||
	else if (e->key() == Qt::Key_Alt || e->key() == Qt::Key_A)
 | 
					 | 
				
			||||||
		ClearAlt();
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return true;
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (e->key() == Qt::Key_Control)
 | 
						if (e->key() == Qt::Key_Control)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		ClearControl();
 | 
							ClearControl();
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -448,8 +416,10 @@ template <typename T>
 | 
				
			|||||||
void GLEmberController<T>::MousePress(QMouseEvent* e)
 | 
					void GLEmberController<T>::MousePress(QMouseEvent* e)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	v3T mouseFlipped(e->x() * m_GL->devicePixelRatio(), m_Viewport[3] - e->y() * m_GL->devicePixelRatio(), 0);//Must flip y because in OpenGL, 0,0 is bottom left, but in windows, it's top left.
 | 
						v3T mouseFlipped(e->x() * m_GL->devicePixelRatio(), m_Viewport[3] - e->y() * m_GL->devicePixelRatio(), 0);//Must flip y because in OpenGL, 0,0 is bottom left, but in windows, it's top left.
 | 
				
			||||||
	Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
 | 
						auto ember = m_FractoriumEmberController->CurrentEmber();
 | 
				
			||||||
	RendererBase* renderer = m_FractoriumEmberController->Renderer();
 | 
						auto xforms = ember->TotalXformCount();
 | 
				
			||||||
 | 
						auto renderer = m_FractoriumEmberController->Renderer();
 | 
				
			||||||
 | 
						size_t i = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//Ensure everything has been initialized.
 | 
						//Ensure everything has been initialized.
 | 
				
			||||||
	if (!renderer)
 | 
						if (!renderer)
 | 
				
			||||||
@ -461,7 +431,6 @@ void GLEmberController<T>::MousePress(QMouseEvent* e)
 | 
				
			|||||||
	m_BoundsDown.x = renderer->LowerLeftY(false);
 | 
						m_BoundsDown.x = renderer->LowerLeftY(false);
 | 
				
			||||||
	m_BoundsDown.y = renderer->UpperRightX(false);
 | 
						m_BoundsDown.y = renderer->UpperRightX(false);
 | 
				
			||||||
	m_BoundsDown.z = renderer->UpperRightY(false);
 | 
						m_BoundsDown.z = renderer->UpperRightY(false);
 | 
				
			||||||
#ifndef OLDDRAG
 | 
					 | 
				
			||||||
	Qt::KeyboardModifiers mod = e->modifiers();
 | 
						Qt::KeyboardModifiers mod = e->modifiers();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mod.testFlag(Qt::ShiftModifier))
 | 
						if (mod.testFlag(Qt::ShiftModifier))
 | 
				
			||||||
@ -472,8 +441,6 @@ void GLEmberController<T>::MousePress(QMouseEvent* e)
 | 
				
			|||||||
	if (mod.testFlag(Qt::AltModifier))// || mod.testFlag(Qt::Key_A))
 | 
						if (mod.testFlag(Qt::AltModifier))// || mod.testFlag(Qt::Key_A))
 | 
				
			||||||
		SetAlt();
 | 
							SetAlt();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (m_DragState == eDragState::DragNone)//Only take action if the user wasn't already dragging.
 | 
						if (m_DragState == eDragState::DragNone)//Only take action if the user wasn't already dragging.
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		m_MouseDownWorldPos = m_MouseWorldPos;//Set the mouse down position to the current position.
 | 
							m_MouseDownWorldPos = m_MouseWorldPos;//Set the mouse down position to the current position.
 | 
				
			||||||
@ -486,11 +453,16 @@ void GLEmberController<T>::MousePress(QMouseEvent* e)
 | 
				
			|||||||
			{
 | 
								{
 | 
				
			||||||
				m_SelectedXform = m_HoverXform;
 | 
									m_SelectedXform = m_HoverXform;
 | 
				
			||||||
				m_DragSrcTransform = Affine2D<T>(m_AffineType == eAffineType::AffinePre ? m_SelectedXform->m_Affine : m_SelectedXform->m_Post);//Copy the affine of the xform that was selected.
 | 
									m_DragSrcTransform = Affine2D<T>(m_AffineType == eAffineType::AffinePre ? m_SelectedXform->m_Affine : m_SelectedXform->m_Post);//Copy the affine of the xform that was selected.
 | 
				
			||||||
				m_DragHandlePos = m_HoverHandlePos;
 | 
					 | 
				
			||||||
				m_DragHandleOffset = m_DragHandlePos - m_MouseWorldPos;
 | 
					 | 
				
			||||||
				m_DragState = eDragState::DragDragging;
 | 
					 | 
				
			||||||
				//The user has selected an xform by clicking on it, so update the main GUI by selecting this xform in the combo box.
 | 
									//The user has selected an xform by clicking on it, so update the main GUI by selecting this xform in the combo box.
 | 
				
			||||||
				m_Fractorium->CurrentXform(xformIndex);
 | 
									m_Fractorium->CurrentXform(xformIndex);//Must do this first so UpdateXform() below properly grabs the current plus any selected.
 | 
				
			||||||
 | 
									//m_DragSrcTransforms.clear();
 | 
				
			||||||
 | 
									//m_FractoriumEmberController->UpdateXform([&](Xform<T>* xform)
 | 
				
			||||||
 | 
									//{
 | 
				
			||||||
 | 
									//	m_DragSrcTransforms.push_back(m_AffineType == eAffineType::AffinePre ? xform->m_Affine : xform->m_Post);
 | 
				
			||||||
 | 
									//}, eXformUpdate::UPDATE_CURRENT_AND_SELECTED, false);//Don't update renderer here.
 | 
				
			||||||
 | 
									m_DragHandlePos = m_HoverHandlePos;//The location in local coordinates of the point selected on the spinner, x, y or center.
 | 
				
			||||||
 | 
									m_DragHandleOffset = m_DragHandlePos - m_MouseWorldPos;//The distance in world coordinates from the point selected to the center of the spinner.
 | 
				
			||||||
 | 
									m_DragState = eDragState::DragDragging;
 | 
				
			||||||
				//Draw large yellow dot on select or drag.
 | 
									//Draw large yellow dot on select or drag.
 | 
				
			||||||
				m_GL->glPointSize(6.0f);
 | 
									m_GL->glPointSize(6.0f);
 | 
				
			||||||
				m_GL->glBegin(GL_POINTS);
 | 
									m_GL->glBegin(GL_POINTS);
 | 
				
			||||||
@ -554,9 +526,7 @@ void GLEmberController<T>::MouseRelease(QMouseEvent* e)
 | 
				
			|||||||
		UpdateHover(mouseFlipped);
 | 
							UpdateHover(mouseFlipped);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	m_DragState = eDragState::DragNone;
 | 
						m_DragState = eDragState::DragNone;
 | 
				
			||||||
#ifndef OLDDRAG
 | 
					 | 
				
			||||||
	m_DragModifier = 0;
 | 
						m_DragModifier = 0;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	m_GL->repaint();//Force immediate redraw.
 | 
						m_GL->repaint();//Force immediate redraw.
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -585,7 +555,7 @@ void GLEmberController<T>::MouseMove(QMouseEvent* e)
 | 
				
			|||||||
	bool draw = true;
 | 
						bool draw = true;
 | 
				
			||||||
	glm::ivec2 mouse(e->x() * m_GL->devicePixelRatio(), e->y() * m_GL->devicePixelRatio());
 | 
						glm::ivec2 mouse(e->x() * m_GL->devicePixelRatio(), e->y() * m_GL->devicePixelRatio());
 | 
				
			||||||
	v3T mouseFlipped(e->x() * m_GL->devicePixelRatio(), m_Viewport[3] - e->y() * m_GL->devicePixelRatio(), 0);//Must flip y because in OpenGL, 0,0 is bottom left, but in windows, it's top left.
 | 
						v3T mouseFlipped(e->x() * m_GL->devicePixelRatio(), m_Viewport[3] - e->y() * m_GL->devicePixelRatio(), 0);//Must flip y because in OpenGL, 0,0 is bottom left, but in windows, it's top left.
 | 
				
			||||||
	Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
 | 
						auto ember = m_FractoriumEmberController->CurrentEmber();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//First check to see if the mouse actually moved.
 | 
						//First check to see if the mouse actually moved.
 | 
				
			||||||
	if (mouse == m_MousePos)
 | 
						if (mouse == m_MousePos)
 | 
				
			||||||
@ -593,7 +563,6 @@ void GLEmberController<T>::MouseMove(QMouseEvent* e)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	m_MousePos = mouse;
 | 
						m_MousePos = mouse;
 | 
				
			||||||
	m_MouseWorldPos = WindowToWorld(mouseFlipped, false);
 | 
						m_MouseWorldPos = WindowToWorld(mouseFlipped, false);
 | 
				
			||||||
	//v3T mouseDelta = m_MouseWorldPos - m_MouseDownWorldPos;//Determine how far the mouse has moved in world cartesian coordinates.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//Update status bar on main window, regardless of whether anything is being dragged.
 | 
						//Update status bar on main window, regardless of whether anything is being dragged.
 | 
				
			||||||
	if (m_Fractorium->m_Controller->RenderTimerRunning())
 | 
						if (m_Fractorium->m_Controller->RenderTimerRunning())
 | 
				
			||||||
@ -605,7 +574,15 @@ void GLEmberController<T>::MouseMove(QMouseEvent* e)
 | 
				
			|||||||
		Affine2D<T>* affine = pre ? &m_SelectedXform->m_Affine : &m_SelectedXform->m_Post;//Determine pre or post affine.
 | 
							Affine2D<T>* affine = pre ? &m_SelectedXform->m_Affine : &m_SelectedXform->m_Post;//Determine pre or post affine.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (m_HoverType == eHoverType::HoverTranslation)
 | 
							if (m_HoverType == eHoverType::HoverTranslation)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								//m_FractoriumEmberController->UpdateXform([&](Xform<T>* xform)
 | 
				
			||||||
 | 
								//{
 | 
				
			||||||
 | 
								//	affine = pre ? &xform->m_Affine : &xform->m_Post;//Determine pre or post affine.
 | 
				
			||||||
 | 
								//	*affine = CalcDragTranslation();
 | 
				
			||||||
 | 
								//}, eXformUpdate::UPDATE_ALL, false);//Don't need to update render for every xform, just do it once below.
 | 
				
			||||||
			*affine = CalcDragTranslation();
 | 
								*affine = CalcDragTranslation();
 | 
				
			||||||
 | 
								//CalcDragTranslation();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		else if (m_HoverType == eHoverType::HoverXAxis)
 | 
							else if (m_HoverType == eHoverType::HoverXAxis)
 | 
				
			||||||
			*affine = CalcDragXAxis();
 | 
								*affine = CalcDragXAxis();
 | 
				
			||||||
		else if (m_HoverType == eHoverType::HoverYAxis)
 | 
							else if (m_HoverType == eHoverType::HoverYAxis)
 | 
				
			||||||
@ -649,7 +626,7 @@ void GLEmberController<T>::MouseMove(QMouseEvent* e)
 | 
				
			|||||||
		if (UpdateHover(mouseFlipped) == -1)
 | 
							if (UpdateHover(mouseFlipped) == -1)
 | 
				
			||||||
			draw = false;
 | 
								draw = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		//Xform<T>* previousHover = m_HoverXform;
 | 
							//auto previousHover = m_HoverXform;
 | 
				
			||||||
		//
 | 
							//
 | 
				
			||||||
		//if (UpdateHover(mouseFlipped) == -1)
 | 
							//if (UpdateHover(mouseFlipped) == -1)
 | 
				
			||||||
		//	m_HoverXform = m_SelectedXform;
 | 
							//	m_HoverXform = m_SelectedXform;
 | 
				
			||||||
@ -690,7 +667,7 @@ void GLWidget::mouseMoveEvent(QMouseEvent* e)
 | 
				
			|||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
void GLEmberController<T>::Wheel(QWheelEvent* e)
 | 
					void GLEmberController<T>::Wheel(QWheelEvent* e)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
 | 
						auto ember = m_FractoriumEmberController->CurrentEmber();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (m_Fractorium && !(e->buttons() & Qt::MiddleButton))//Middle button does whole image translation, so ignore the mouse wheel while panning to avoid inadvertent zooming.
 | 
						if (m_Fractorium && !(e->buttons() & Qt::MiddleButton))//Middle button does whole image translation, so ignore the mouse wheel while panning to avoid inadvertent zooming.
 | 
				
			||||||
		m_Fractorium->SetScale(ember->m_PixelsPerUnit + (e->angleDelta().y() >= 0 ? 50 : -50));
 | 
							m_Fractorium->SetScale(ember->m_PixelsPerUnit + (e->angleDelta().y() >= 0 ? 50 : -50));
 | 
				
			||||||
@ -822,7 +799,7 @@ void GLWidget::SetViewport()
 | 
				
			|||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
bool GLEmberController<T>::SizesMatch()
 | 
					bool GLEmberController<T>::SizesMatch()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
 | 
						auto ember = m_FractoriumEmberController->CurrentEmber();
 | 
				
			||||||
	return (ember &&
 | 
						return (ember &&
 | 
				
			||||||
			ember->m_FinalRasW == m_GL->width() &&
 | 
								ember->m_FinalRasW == m_GL->width() &&
 | 
				
			||||||
			ember->m_FinalRasH == m_GL->height() &&
 | 
								ember->m_FinalRasH == m_GL->height() &&
 | 
				
			||||||
@ -837,12 +814,13 @@ bool GLEmberController<T>::SizesMatch()
 | 
				
			|||||||
/// The frequency of the grid lines will change depending on the zoom.
 | 
					/// The frequency of the grid lines will change depending on the zoom.
 | 
				
			||||||
/// Calculated with the frame always centered, the renderer just moves the camera.
 | 
					/// Calculated with the frame always centered, the renderer just moves the camera.
 | 
				
			||||||
/// </summary>
 | 
					/// </summary>
 | 
				
			||||||
void GLWidget::DrawGrid()
 | 
					/// <param name="scale">A value to scale by, used when locking the affine scale</param>
 | 
				
			||||||
 | 
					void GLWidget::DrawGrid(double scale)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	RendererBase* renderer = m_Fractorium->m_Controller->Renderer();
 | 
						RendererBase* renderer = m_Fractorium->m_Controller->Renderer();
 | 
				
			||||||
	float unitX = std::abs(renderer->UpperRightX(false) - renderer->LowerLeftX(false)) / 2.0f;
 | 
						float unitX = std::abs(renderer->UpperRightX(false) - renderer->LowerLeftX(false)) / 2.0f;
 | 
				
			||||||
	float unitY = std::abs(renderer->UpperRightY(false) - renderer->LowerLeftY(false)) / 2.0f;
 | 
						float unitY = std::abs(renderer->UpperRightY(false) - renderer->LowerLeftY(false)) / 2.0f;
 | 
				
			||||||
	float rad = std::max(unitX, unitY);
 | 
						float rad = std::max(unitX * scale, unitY * scale);
 | 
				
			||||||
	float xLow =  floor(-unitX);
 | 
						float xLow =  floor(-unitX);
 | 
				
			||||||
	float xHigh = ceil(unitX);
 | 
						float xHigh = ceil(unitX);
 | 
				
			||||||
	float yLow =  floor(-unitY);
 | 
						float yLow =  floor(-unitY);
 | 
				
			||||||
@ -866,6 +844,9 @@ void GLWidget::DrawGrid()
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						unitX *= scale;
 | 
				
			||||||
 | 
						unitY *= scale;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (unitX <= 64.0f)
 | 
						if (unitX <= 64.0f)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		glColor4f(0.5f, 0.5f, 0.5f, 1.0f);
 | 
							glColor4f(0.5f, 0.5f, 0.5f, 1.0f);
 | 
				
			||||||
@ -934,16 +915,16 @@ void GLWidget::DrawUnitSquare()
 | 
				
			|||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
void GLEmberController<T>::DrawAffine(Xform<T>* xform, bool pre, bool selected)
 | 
					void GLEmberController<T>::DrawAffine(Xform<T>* xform, bool pre, bool selected)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
 | 
						auto ember = m_FractoriumEmberController->CurrentEmber();
 | 
				
			||||||
	bool final = ember->IsFinalXform(xform);
 | 
						bool final = ember->IsFinalXform(xform);
 | 
				
			||||||
	int index = ember->GetXformIndex(xform);
 | 
						int index = ember->GetXformIndex(xform);
 | 
				
			||||||
	size_t size = ember->m_Palette.m_Entries.size();
 | 
						size_t size = ember->m_Palette.m_Entries.size();
 | 
				
			||||||
	v4T color = ember->m_Palette.m_Entries[Clamp<T>(xform->m_ColorX * size, 0, size - 1)];
 | 
						v4T color = ember->m_Palette.m_Entries[Clamp<T>(xform->m_ColorX * size, 0, size - 1)];
 | 
				
			||||||
	Affine2D<T>* affine = pre ? &xform->m_Affine : &xform->m_Post;
 | 
						auto affine = pre ? &xform->m_Affine : &xform->m_Post;
 | 
				
			||||||
	//For some incredibly strange reason, even though glm and OpenGL use matrices with a column-major
 | 
						//For some incredibly strange reason, even though glm and OpenGL use matrices with a column-major
 | 
				
			||||||
	//data layout, nothing will work here unless they are flipped to row major order. This is how it was
 | 
						//data layout, nothing will work here unless they are flipped to row major order. This is how it was
 | 
				
			||||||
	//done in Fractron.
 | 
						//done in Fractron.
 | 
				
			||||||
	m4T mat = affine->ToMat4RowMajor();
 | 
						m4T mat = (*affine * m_FractoriumEmberController->AffineScaleCurrentToLocked()).ToMat4RowMajor();
 | 
				
			||||||
	m_GL->glPushMatrix();
 | 
						m_GL->glPushMatrix();
 | 
				
			||||||
	m_GL->glLoadIdentity();
 | 
						m_GL->glLoadIdentity();
 | 
				
			||||||
	MultMatrix(mat);
 | 
						MultMatrix(mat);
 | 
				
			||||||
@ -1054,7 +1035,7 @@ int GLEmberController<T>::UpdateHover(v3T& glCoords)
 | 
				
			|||||||
	bool postAll = post && m_Fractorium->DrawAllPost();
 | 
						bool postAll = post && m_Fractorium->DrawAllPost();
 | 
				
			||||||
	uint bestIndex = -1;
 | 
						uint bestIndex = -1;
 | 
				
			||||||
	T bestDist = 10;
 | 
						T bestDist = 10;
 | 
				
			||||||
	Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
 | 
						auto ember = m_FractoriumEmberController->CurrentEmber();
 | 
				
			||||||
	m_HoverType = eHoverType::HoverNone;
 | 
						m_HoverType = eHoverType::HoverNone;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//If there's a selected/current xform, check it first so it gets precedence over the others.
 | 
						//If there's a selected/current xform, check it first so it gets precedence over the others.
 | 
				
			||||||
@ -1076,7 +1057,7 @@ int GLEmberController<T>::UpdateHover(v3T& glCoords)
 | 
				
			|||||||
	//Check all xforms.
 | 
						//Check all xforms.
 | 
				
			||||||
	for (size_t i = 0; i < ember->TotalXformCount(); i++)
 | 
						for (size_t i = 0; i < ember->TotalXformCount(); i++)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Xform<T>* xform = ember->GetTotalXform(i);
 | 
							auto xform = ember->GetTotalXform(i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (preAll || (pre && m_HoverXform == xform))//Only check pre affine if they are shown.
 | 
							if (preAll || (pre && m_HoverXform == xform))//Only check pre affine if they are shown.
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@ -1116,17 +1097,17 @@ template <typename T>
 | 
				
			|||||||
bool GLEmberController<T>::CheckXformHover(Xform<T>* xform, v3T& glCoords, T& bestDist, bool pre, bool post)
 | 
					bool GLEmberController<T>::CheckXformHover(Xform<T>* xform, v3T& glCoords, T& bestDist, bool pre, bool post)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	bool preFound = false, postFound = false;
 | 
						bool preFound = false, postFound = false;
 | 
				
			||||||
	float dist = 0.0f;
 | 
						T dist = 0, scale = m_FractoriumEmberController->AffineScaleCurrentToLocked();
 | 
				
			||||||
	v3T pos;
 | 
						v3T pos;
 | 
				
			||||||
	Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pre)
 | 
						if (pre)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		v3T translation(xform->m_Affine.C()/* - ember->m_CenterX*/, /*ember->m_CenterY + */xform->m_Affine.F(), 0);
 | 
							auto affineScaled = xform->m_Affine * scale;
 | 
				
			||||||
 | 
							v3T translation(affineScaled.C(), affineScaled.F(), 0);
 | 
				
			||||||
		v3T transScreen = glm::project(translation, m_Modelview, m_Projection, m_Viewport);
 | 
							v3T transScreen = glm::project(translation, m_Modelview, m_Projection, m_Viewport);
 | 
				
			||||||
		v3T xAxis(xform->m_Affine.A(), xform->m_Affine.D(), 0);
 | 
							v3T xAxis(affineScaled.A(), affineScaled.D(), 0);
 | 
				
			||||||
		v3T xAxisScreen = glm::project(translation + xAxis, m_Modelview, m_Projection, m_Viewport);
 | 
							v3T xAxisScreen = glm::project(translation + xAxis, m_Modelview, m_Projection, m_Viewport);
 | 
				
			||||||
		v3T yAxis(xform->m_Affine.B(), xform->m_Affine.E(), 0);
 | 
							v3T yAxis(affineScaled.B(), affineScaled.E(), 0);
 | 
				
			||||||
		v3T yAxisScreen = glm::project(translation + yAxis, m_Modelview, m_Projection, m_Viewport);
 | 
							v3T yAxisScreen = glm::project(translation + yAxis, m_Modelview, m_Projection, m_Viewport);
 | 
				
			||||||
		pos = translation;
 | 
							pos = translation;
 | 
				
			||||||
		dist = glm::distance(glCoords, transScreen);
 | 
							dist = glm::distance(glCoords, transScreen);
 | 
				
			||||||
@ -1167,11 +1148,12 @@ bool GLEmberController<T>::CheckXformHover(Xform<T>* xform, v3T& glCoords, T& be
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (post)
 | 
						if (post)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		v3T translation(xform->m_Post.C()/* - ember->m_CenterX*/, /*ember->m_CenterY + */xform->m_Post.F(), 0);
 | 
							auto affineScaled = xform->m_Post * scale;
 | 
				
			||||||
 | 
							v3T translation(affineScaled.C(), affineScaled.F(), 0);
 | 
				
			||||||
		v3T transScreen = glm::project(translation, m_Modelview, m_Projection, m_Viewport);
 | 
							v3T transScreen = glm::project(translation, m_Modelview, m_Projection, m_Viewport);
 | 
				
			||||||
		v3T xAxis(xform->m_Post.A(), xform->m_Post.D(), 0);
 | 
							v3T xAxis(affineScaled.A(), affineScaled.D(), 0);
 | 
				
			||||||
		v3T xAxisScreen = glm::project(translation + xAxis, m_Modelview, m_Projection, m_Viewport);
 | 
							v3T xAxisScreen = glm::project(translation + xAxis, m_Modelview, m_Projection, m_Viewport);
 | 
				
			||||||
		v3T yAxis(xform->m_Post.B(), xform->m_Post.E(), 0);
 | 
							v3T yAxis(affineScaled.B(), affineScaled.E(), 0);
 | 
				
			||||||
		v3T yAxisScreen = glm::project(translation + yAxis, m_Modelview, m_Projection, m_Viewport);
 | 
							v3T yAxisScreen = glm::project(translation + yAxis, m_Modelview, m_Projection, m_Viewport);
 | 
				
			||||||
		pos = translation;
 | 
							pos = translation;
 | 
				
			||||||
		dist = glm::distance(glCoords, transScreen);
 | 
							dist = glm::distance(glCoords, transScreen);
 | 
				
			||||||
@ -1235,7 +1217,8 @@ template <typename T>
 | 
				
			|||||||
Affine2D<T> GLEmberController<T>::CalcDragXAxis()
 | 
					Affine2D<T> GLEmberController<T>::CalcDragXAxis()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	v3T t3, newAxis, newPos;
 | 
						v3T t3, newAxis, newPos;
 | 
				
			||||||
	Affine2D<T> result = m_DragSrcTransform;
 | 
						auto scale = m_FractoriumEmberController->AffineScaleLockedToCurrent();
 | 
				
			||||||
 | 
						auto result = m_DragSrcTransform;
 | 
				
			||||||
	bool worldPivotShiftAlt = !m_Fractorium->LocalPivot() && GetShift() && GetAlt();
 | 
						bool worldPivotShiftAlt = !m_Fractorium->LocalPivot() && GetShift() && GetAlt();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (worldPivotShiftAlt)
 | 
						if (worldPivotShiftAlt)
 | 
				
			||||||
@ -1245,7 +1228,7 @@ Affine2D<T> GLEmberController<T>::CalcDragXAxis()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (GetShift())
 | 
						if (GetShift())
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		v3T targetAxis = m_MouseWorldPos - t3;
 | 
							v3T targetAxis = (m_MouseWorldPos * scale) - t3;
 | 
				
			||||||
		v3T norm = glm::normalize(targetAxis);
 | 
							v3T norm = glm::normalize(targetAxis);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (GetControl())
 | 
							if (GetControl())
 | 
				
			||||||
@ -1263,7 +1246,7 @@ Affine2D<T> GLEmberController<T>::CalcDragXAxis()
 | 
				
			|||||||
		else
 | 
							else
 | 
				
			||||||
			newPos = m_MouseWorldPos + m_DragHandleOffset;
 | 
								newPos = m_MouseWorldPos + m_DragHandleOffset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		newAxis = newPos - t3;
 | 
							newAxis = (newPos * scale) - t3;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (GetAlt())
 | 
						if (GetAlt())
 | 
				
			||||||
@ -1278,7 +1261,8 @@ Affine2D<T> GLEmberController<T>::CalcDragXAxis()
 | 
				
			|||||||
		result.RotateScaleXTo(v2T(newAxis));
 | 
							result.RotateScaleXTo(v2T(newAxis));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	m_DragHandlePos = v3T(result.O() + result.X(), 0);
 | 
						T scaleBack = m_FractoriumEmberController->AffineScaleCurrentToLocked();
 | 
				
			||||||
 | 
						m_DragHandlePos = v3T((result.O() + result.X()) * scaleBack, 0);
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1304,7 +1288,8 @@ template <typename T>
 | 
				
			|||||||
Affine2D<T> GLEmberController<T>::CalcDragYAxis()
 | 
					Affine2D<T> GLEmberController<T>::CalcDragYAxis()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	v3T t3, newAxis, newPos;
 | 
						v3T t3, newAxis, newPos;
 | 
				
			||||||
	Affine2D<T> result = m_DragSrcTransform;
 | 
						auto scale = m_FractoriumEmberController->AffineScaleLockedToCurrent();
 | 
				
			||||||
 | 
						auto result = m_DragSrcTransform;
 | 
				
			||||||
	bool worldPivotShiftAlt = !m_Fractorium->LocalPivot() && GetShift() && GetAlt();
 | 
						bool worldPivotShiftAlt = !m_Fractorium->LocalPivot() && GetShift() && GetAlt();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (worldPivotShiftAlt)
 | 
						if (worldPivotShiftAlt)
 | 
				
			||||||
@ -1314,7 +1299,7 @@ Affine2D<T> GLEmberController<T>::CalcDragYAxis()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (GetShift())
 | 
						if (GetShift())
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		v3T targetAxis = m_MouseWorldPos - t3;
 | 
							v3T targetAxis = (m_MouseWorldPos * scale) - t3;
 | 
				
			||||||
		v3T norm = glm::normalize(targetAxis);
 | 
							v3T norm = glm::normalize(targetAxis);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (GetControl())
 | 
							if (GetControl())
 | 
				
			||||||
@ -1332,7 +1317,7 @@ Affine2D<T> GLEmberController<T>::CalcDragYAxis()
 | 
				
			|||||||
		else
 | 
							else
 | 
				
			||||||
			newPos = m_MouseWorldPos + m_DragHandleOffset;
 | 
								newPos = m_MouseWorldPos + m_DragHandleOffset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		newAxis = newPos - t3;
 | 
							newAxis = (newPos * scale) - t3;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (GetAlt())
 | 
						if (GetAlt())
 | 
				
			||||||
@ -1347,7 +1332,8 @@ Affine2D<T> GLEmberController<T>::CalcDragYAxis()
 | 
				
			|||||||
		result.RotateScaleYTo(v2T(newAxis));
 | 
							result.RotateScaleYTo(v2T(newAxis));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	m_DragHandlePos = v3T(result.O() + result.Y(), 0);
 | 
						T scaleBack = m_FractoriumEmberController->AffineScaleCurrentToLocked();
 | 
				
			||||||
 | 
						m_DragHandlePos = v3T((result.O() + result.Y()) * scaleBack, 0);
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1368,8 +1354,9 @@ Affine2D<T> GLEmberController<T>::CalcDragYAxis()
 | 
				
			|||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
Affine2D<T> GLEmberController<T>::CalcDragTranslation()
 | 
					Affine2D<T> GLEmberController<T>::CalcDragTranslation()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	v3T newPos, newX, newY;
 | 
						v3T newPos;
 | 
				
			||||||
	Affine2D<T> result = m_DragSrcTransform;
 | 
						auto scale = m_FractoriumEmberController->AffineScaleLockedToCurrent();
 | 
				
			||||||
 | 
						auto result = m_DragSrcTransform;
 | 
				
			||||||
	bool worldPivotShift = !m_Fractorium->LocalPivot() && GetShift();
 | 
						bool worldPivotShift = !m_Fractorium->LocalPivot() && GetShift();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (GetShift())
 | 
						if (GetShift())
 | 
				
			||||||
@ -1387,17 +1374,32 @@ Affine2D<T> GLEmberController<T>::CalcDragTranslation()
 | 
				
			|||||||
			T endAngle = atan2(newPos.y, newPos.x);
 | 
								T endAngle = atan2(newPos.y, newPos.x);
 | 
				
			||||||
			T angle = startAngle - endAngle;
 | 
								T angle = startAngle - endAngle;
 | 
				
			||||||
			result.Rotate(angle * RAD_2_DEG);
 | 
								result.Rotate(angle * RAD_2_DEG);
 | 
				
			||||||
 | 
								//RotateXformsByAngle
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (GetControl())
 | 
							if (GetControl())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
			newPos = SnapToGrid(m_MouseWorldPos);
 | 
								newPos = SnapToGrid(m_MouseWorldPos);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
			newPos = m_MouseWorldPos + m_DragHandleOffset;
 | 
								newPos = m_MouseWorldPos + m_DragHandleOffset;
 | 
				
			||||||
 | 
								//bool pre = m_AffineType == eAffineType::AffinePre;
 | 
				
			||||||
 | 
								//size_t index = 0;
 | 
				
			||||||
 | 
								//newPos = m_MouseWorldPos;
 | 
				
			||||||
 | 
								//auto diff = m_MouseWorldPos - m_MouseDownWorldPos;
 | 
				
			||||||
 | 
								//m_FractoriumEmberController->UpdateXform([&](Xform<T>* xform)
 | 
				
			||||||
 | 
								//{
 | 
				
			||||||
 | 
								//	auto affine = pre ? &xform->m_Affine : &xform->m_Post;//Determine pre or post affine.
 | 
				
			||||||
 | 
								//	affine->O(m_DragSrcTransforms[index++].O() + v2T(diff));
 | 
				
			||||||
 | 
								//}, eXformUpdate::UPDATE_CURRENT_AND_SELECTED, false);//Don't need to update render for every xform, just do it once below.
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	result.O(v2T(newPos));
 | 
						T scaleBack = m_FractoriumEmberController->AffineScaleCurrentToLocked();
 | 
				
			||||||
 | 
						result.O(v2T(newPos * scale));
 | 
				
			||||||
	m_DragHandlePos = newPos;
 | 
						m_DragHandlePos = newPos;
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -69,7 +69,7 @@ private:
 | 
				
			|||||||
	bool Allocate(bool force = false);
 | 
						bool Allocate(bool force = false);
 | 
				
			||||||
	bool Deallocate();
 | 
						bool Deallocate();
 | 
				
			||||||
	void SetViewport();
 | 
						void SetViewport();
 | 
				
			||||||
	void DrawGrid();
 | 
						void DrawGrid(double scale);
 | 
				
			||||||
	void DrawUnitSquare();
 | 
						void DrawUnitSquare();
 | 
				
			||||||
	void DrawAffineHelper(int index, bool selected, bool pre, bool final, bool background);
 | 
						void DrawAffineHelper(int index, bool selected, bool pre, bool final, bool background);
 | 
				
			||||||
	GLEmberControllerBase* GLController();
 | 
						GLEmberControllerBase* GLController();
 | 
				
			||||||
 | 
				
			|||||||
@ -56,7 +56,7 @@ void FractoriumVariationsDialog::ForEachSelectedCell(std::function<void(QTableWi
 | 
				
			|||||||
	QList<QTableWidgetItem*> selectedItems = table->selectedItems();
 | 
						QList<QTableWidgetItem*> selectedItems = table->selectedItems();
 | 
				
			||||||
	table->model()->blockSignals(true);
 | 
						table->model()->blockSignals(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	foreach (QTableWidgetItem* item, selectedItems)
 | 
						for (auto item : selectedItems)
 | 
				
			||||||
		if (item)
 | 
							if (item)
 | 
				
			||||||
			func(item);
 | 
								func(item);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user