mirror of
				https://bitbucket.org/mfeemster/fractorium.git
				synced 2025-10-31 17:30:24 -04:00 
			
		
		
		
	--Bug fixes
-Fix crash on palette editor when opening it with certain palette files in a particular order. -An xform with only a post variation in it might have showed up wrong. -The xforms combo box was obscuring the name of the xforms by not being wide enough. -Make variation state preservation be a little bit more correct in OpenCL. --Code changes -Make all iterators on the CPU use a temporary point.
This commit is contained in:
		| @ -1,6 +1,6 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> | ||||
| 	<?define ProductVersion="1.0.0.18" ?> | ||||
| 	<?define ProductVersion="1.0.0.19" ?> | ||||
| 	<?define ProductName="Fractorium $(var.ProductVersion) ($(var.GpuType))" ?> | ||||
| 	<?define UpgradeCode="{4714cd15-bfba-44f6-8059-9e1466ebfa6e}"?> | ||||
| 	<?define Manufacturer="Fractorium"?> | ||||
| @ -13,7 +13,7 @@ | ||||
| 	<!-- | ||||
| 	Change this for every release. | ||||
| 	--> | ||||
| 	<?define ProductCode="{B0ECFACF-9166-4AE2-A1BF-FF0C8D87FFDF}"?> | ||||
| 	<?define ProductCode="{8A8580F6-017D-455D-899E-C0FF91ECEB68}"?> | ||||
| 	 | ||||
| 	<Product Id="$(var.ProductCode)" Name="$(var.ProductName)" Language="1033" Version="$(var.ProductVersion)" Manufacturer="$(var.Manufacturer)" UpgradeCode="$(var.UpgradeCode)"> | ||||
| 		<Package | ||||
|  | ||||
										
											Binary file not shown.
										
									
								
							| @ -49,8 +49,8 @@ | ||||
| 	// | ||||
|  | ||||
| 	VS_VERSION_INFO VERSIONINFO | ||||
| 	FILEVERSION 1, 0, 0, 18 | ||||
| 	PRODUCTVERSION 1, 0, 0, 18 | ||||
| 	FILEVERSION 1, 0, 0, 19 | ||||
| 	PRODUCTVERSION 1, 0, 0, 19 | ||||
| 	FILEFLAGSMASK 0x3fL | ||||
| 	#ifdef _DEBUG | ||||
| 		FILEFLAGS 0x1L | ||||
| @ -67,12 +67,12 @@ | ||||
| 	BEGIN | ||||
| 	VALUE "CompanyName", "Open Source" | ||||
| 	VALUE "FileDescription", "Renders fractal flames as animations with motion blur" | ||||
| 	VALUE "FileVersion", "1, 0, 0, 18" | ||||
| 	VALUE "FileVersion", "1, 0, 0, 19" | ||||
| 	VALUE "InternalName", "EmberAnimate.exe" | ||||
| 	VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2019, GPL v3" | ||||
| 	VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2020, GPL v3" | ||||
| 	VALUE "OriginalFilename", "EmberAnimate.exe" | ||||
| 	VALUE "ProductName", "Ember Animate" | ||||
| 	VALUE "ProductVersion", "1, 0, 0, 18" | ||||
| 	VALUE "ProductVersion", "1, 0, 0, 19" | ||||
| 	END | ||||
| 	END | ||||
| 	BLOCK "VarFileInfo" | ||||
|  | ||||
										
											Binary file not shown.
										
									
								
							| @ -49,8 +49,8 @@ | ||||
| 	// | ||||
|  | ||||
| 	VS_VERSION_INFO VERSIONINFO | ||||
| 	FILEVERSION 1, 0, 0, 18 | ||||
| 	PRODUCTVERSION 1, 0, 0, 18 | ||||
| 	FILEVERSION 1, 0, 0, 19 | ||||
| 	PRODUCTVERSION 1, 0, 0, 19 | ||||
| 	FILEFLAGSMASK 0x3fL | ||||
| 	#ifdef _DEBUG | ||||
| 		FILEFLAGS 0x1L | ||||
| @ -66,13 +66,13 @@ | ||||
| 	BLOCK "040904b0" | ||||
| 	BEGIN | ||||
| 	VALUE "CompanyName", "Open Source" | ||||
| 	VALUE "FileDescription", "Manipulates fractal flames parameter files" | ||||
| 	VALUE "FileVersion", "1, 0, 0, 18" | ||||
| 	VALUE "FileDescription", "Manipulates fractal flame parameter files" | ||||
| 	VALUE "FileVersion", "1, 0, 0, 19" | ||||
| 	VALUE "InternalName", "EmberGenome.exe" | ||||
| 	VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2019, GPL v3" | ||||
| 	VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2020, GPL v3" | ||||
| 	VALUE "OriginalFilename", "EmberGenome.exe" | ||||
| 	VALUE "ProductName", "Ember Genome" | ||||
| 	VALUE "ProductVersion", "1, 0, 0, 18" | ||||
| 	VALUE "ProductVersion", "1, 0, 0, 19" | ||||
| 	END | ||||
| 	END | ||||
| 	BLOCK "VarFileInfo" | ||||
|  | ||||
| @ -49,8 +49,8 @@ | ||||
| 	// | ||||
|  | ||||
| 	VS_VERSION_INFO VERSIONINFO | ||||
| 	FILEVERSION 1, 0, 0, 18 | ||||
| 	PRODUCTVERSION 1, 0, 0, 18 | ||||
| 	FILEVERSION 1, 0, 0, 19 | ||||
| 	PRODUCTVERSION 1, 0, 0, 19 | ||||
| 	FILEFLAGSMASK 0x3fL | ||||
| 	#ifdef _DEBUG | ||||
| 		FILEFLAGS 0x1L | ||||
| @ -67,12 +67,12 @@ | ||||
| 	BEGIN | ||||
| 	VALUE "CompanyName", "Open Source" | ||||
| 	VALUE "FileDescription", "Renders fractal flames as single images" | ||||
| 	VALUE "FileVersion", "1, 0, 0, 18" | ||||
| 	VALUE "FileVersion", "1, 0, 0, 19" | ||||
| 	VALUE "InternalName", "EmberRender.exe" | ||||
| 	VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2019, GPL v3" | ||||
| 	VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2020, GPL v3" | ||||
| 	VALUE "OriginalFilename", "EmberRender.exe" | ||||
| 	VALUE "ProductName", "Ember Render" | ||||
| 	VALUE "ProductVersion", "1, 0, 0, 18" | ||||
| 	VALUE "ProductVersion", "1, 0, 0, 19" | ||||
| 	END | ||||
| 	END | ||||
| 	BLOCK "VarFileInfo" | ||||
|  | ||||
										
											Binary file not shown.
										
									
								
							| @ -37,7 +37,7 @@ static void sincos(float x, float* s, float* c) | ||||
|  | ||||
| namespace EmberNs | ||||
| { | ||||
| #define EMBER_VERSION "1.0.0.18" | ||||
| #define EMBER_VERSION "1.0.0.19" | ||||
| //#define FLAM3_COMPAT 1//Uncomment this if you want full compatibility with flam3 regarding some of the trig-based variations in Variations01.h | ||||
| #define EPS6 T(1e-6) | ||||
| #define EPS std::numeric_limits<T>::epsilon()//Apoplugin.h uses -20, but it's more mathematically correct to do it this way. | ||||
|  | ||||
| @ -300,7 +300,7 @@ public: | ||||
| 	virtual size_t Iterate(Ember<T>& ember, const IterParams<T> params, const CarToRas<T>& ctr, Point<T>* samples, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override | ||||
| 	{ | ||||
| 		size_t i, badVals = 0; | ||||
| 		Point<T> tempPoint, p1; | ||||
| 		Point<T> tempPoint, p1, p2; | ||||
| 		auto xforms = ember.NonConstXforms(); | ||||
|  | ||||
| 		if (ember.ProjBits())//No xaos, 3D. | ||||
| @ -311,8 +311,10 @@ public: | ||||
|  | ||||
| 				for (i = 0; i < params.m_Skip; i++)//Fuse. | ||||
| 				{ | ||||
| 					if (xforms[NextXformFromIndex(rand.Rand())].Apply(&p1, &p1, rand)) | ||||
| 						DoBadVals(xforms, ember.m_RandPointRange, badVals, &p1, rand); | ||||
| 					if (xforms[NextXformFromIndex(rand.Rand())].Apply(&p1, &p2, rand)) | ||||
| 						DoBadVals(xforms, ember.m_RandPointRange, badVals, &p2, rand); | ||||
|  | ||||
| 					p1 = p2; | ||||
| 				} | ||||
|  | ||||
| 				DoFinalXform(ember, p1, samples, rand);//Apply to last fuse point and store as the first element in samples. | ||||
| @ -320,10 +322,11 @@ public: | ||||
|  | ||||
| 				for (i = 1; i < params.m_Count; i++)//Real loop. | ||||
| 				{ | ||||
| 					if (xforms[NextXformFromIndex(rand.Rand())].Apply(&p1, &p1, rand)) | ||||
| 						DoBadVals(xforms, ember.m_RandPointRange, badVals, &p1, rand); | ||||
| 					if (xforms[NextXformFromIndex(rand.Rand())].Apply(&p1, &p2, rand)) | ||||
| 						DoBadVals(xforms, ember.m_RandPointRange, badVals, &p2, rand); | ||||
|  | ||||
| 					DoFinalXform(ember, p1, samples + i, rand); | ||||
| 					p1 = p2; | ||||
| 					DoFinalXform(ember, p2, samples + i, rand); | ||||
| 					ember.Proj(samples[i], rand, ctr); | ||||
| 				} | ||||
| 			} | ||||
| @ -333,8 +336,10 @@ public: | ||||
|  | ||||
| 				for (i = 0; i < params.m_Skip; i++)//Fuse. | ||||
| 				{ | ||||
| 					if (xforms[NextXformFromIndex(rand.Rand())].Apply(&p1, &p1, rand)) | ||||
| 						DoBadVals(xforms, ember.m_RandPointRange, badVals, &p1, rand); | ||||
| 					if (xforms[NextXformFromIndex(rand.Rand())].Apply(&p1, &p2, rand)) | ||||
| 						DoBadVals(xforms, ember.m_RandPointRange, badVals, &p2, rand); | ||||
|  | ||||
| 					p1 = p2; | ||||
| 				} | ||||
|  | ||||
| 				samples[0] = p1; | ||||
| @ -358,18 +363,21 @@ public: | ||||
|  | ||||
| 				for (i = 0; i < params.m_Skip; i++)//Fuse. | ||||
| 				{ | ||||
| 					if (xforms[NextXformFromIndex(rand.Rand())].Apply(&p1, &p1, rand)) | ||||
| 						DoBadVals(xforms, ember.m_RandPointRange, badVals, &p1, rand); | ||||
| 					if (xforms[NextXformFromIndex(rand.Rand())].Apply(&p1, &p2, rand)) | ||||
| 						DoBadVals(xforms, ember.m_RandPointRange, badVals, &p2, rand); | ||||
|  | ||||
| 					p1 = p2; | ||||
| 				} | ||||
|  | ||||
| 				DoFinalXform(ember, p1, samples, rand);//Apply to last fuse point and store as the first element in samples. | ||||
|  | ||||
| 				for (i = 1; i < params.m_Count; i++)//Real loop. | ||||
| 				{ | ||||
| 					if (xforms[NextXformFromIndex(rand.Rand())].Apply(&p1, &p1, rand))//Feed the resulting value of applying the randomly selected xform back into the next iter, and not the result of applying the final xform. | ||||
| 						DoBadVals(xforms, ember.m_RandPointRange, badVals, &p1, rand); | ||||
| 					if (xforms[NextXformFromIndex(rand.Rand())].Apply(&p1, &p2, rand))//Feed the resulting value of applying the randomly selected xform back into the next iter, and not the result of applying the final xform. | ||||
| 						DoBadVals(xforms, ember.m_RandPointRange, badVals, &p2, rand); | ||||
|  | ||||
| 					DoFinalXform(ember, p1, samples + i, rand); | ||||
| 					p1 = p2; | ||||
| 					DoFinalXform(ember, p2, samples + i, rand); | ||||
| 				} | ||||
| 			} | ||||
| 			else//No xaos, no 3D, no final. | ||||
| @ -378,8 +386,10 @@ public: | ||||
|  | ||||
| 				for (i = 0; i < params.m_Skip; i++)//Fuse. | ||||
| 				{ | ||||
| 					if (xforms[NextXformFromIndex(rand.Rand())].Apply(&p1, &p1, rand)) | ||||
| 						DoBadVals(xforms, ember.m_RandPointRange, badVals, &p1, rand); | ||||
| 					if (xforms[NextXformFromIndex(rand.Rand())].Apply(&p1, &p2, rand)) | ||||
| 						DoBadVals(xforms, ember.m_RandPointRange, badVals, &p2, rand); | ||||
|  | ||||
| 					p1 = p2; | ||||
| 				} | ||||
|  | ||||
| 				samples[0] = p1; | ||||
| @ -468,7 +478,7 @@ public: | ||||
| 		size_t i, xformIndex; | ||||
| 		size_t lastXformUsed = 0; | ||||
| 		size_t badVals = 0; | ||||
| 		Point<T> tempPoint, p1; | ||||
| 		Point<T> tempPoint, p1, p2; | ||||
| 		auto xforms = ember.NonConstXforms(); | ||||
|  | ||||
| 		if (ember.ProjBits())//Xaos, 3D. | ||||
| @ -481,9 +491,10 @@ public: | ||||
| 				{ | ||||
| 					xformIndex = NextXformFromIndex(rand.Rand(), lastXformUsed); | ||||
|  | ||||
| 					if (xforms[xformIndex].Apply(&p1, &p1, rand)) | ||||
| 						DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p1, rand); | ||||
| 					if (xforms[xformIndex].Apply(&p1, &p2, rand)) | ||||
| 						DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p2, rand); | ||||
|  | ||||
| 					p1 = p2; | ||||
| 					lastXformUsed = xformIndex + 1;//Store the last used transform. | ||||
| 				} | ||||
|  | ||||
| @ -494,10 +505,11 @@ public: | ||||
| 				{ | ||||
| 					xformIndex = NextXformFromIndex(rand.Rand(), lastXformUsed); | ||||
|  | ||||
| 					if (xforms[xformIndex].Apply(&p1, &p1, rand))//Feed the resulting value of applying the randomly selected xform back into the next iter, and not the result of applying the final xform. | ||||
| 						DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p1, rand); | ||||
| 					if (xforms[xformIndex].Apply(&p1, &p2, rand))//Feed the resulting value of applying the randomly selected xform back into the next iter, and not the result of applying the final xform. | ||||
| 						DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p2, rand); | ||||
|  | ||||
| 					DoFinalXform(ember, p1, samples + i, rand); | ||||
| 					p1 = p2; | ||||
| 					DoFinalXform(ember, p2, samples + i, rand); | ||||
| 					ember.Proj(samples[i], rand, ctr); | ||||
| 					lastXformUsed = xformIndex + 1;//Store the last used transform. | ||||
| 				} | ||||
| @ -510,9 +522,10 @@ public: | ||||
| 				{ | ||||
| 					xformIndex = NextXformFromIndex(rand.Rand(), lastXformUsed); | ||||
|  | ||||
| 					if (xforms[xformIndex].Apply(&p1, &p1, rand)) | ||||
| 						DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p1, rand); | ||||
| 					if (xforms[xformIndex].Apply(&p1, &p2, rand)) | ||||
| 						DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p2, rand); | ||||
|  | ||||
| 					p1 = p2; | ||||
| 					lastXformUsed = xformIndex + 1;//Store the last used transform. | ||||
| 				} | ||||
|  | ||||
| @ -523,10 +536,10 @@ public: | ||||
| 				{ | ||||
| 					xformIndex = NextXformFromIndex(rand.Rand(), lastXformUsed); | ||||
|  | ||||
| 					if (xforms[xformIndex].Apply(&p1, &p1, rand)) | ||||
| 						DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p1, rand); | ||||
| 					if (xforms[xformIndex].Apply(&p1, &p2, rand)) | ||||
| 						DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p2, rand); | ||||
|  | ||||
| 					samples[i] = p1; | ||||
| 					samples[i] = p1 = p2; | ||||
| 					ember.Proj(samples[i], rand, ctr); | ||||
| 					lastXformUsed = xformIndex + 1;//Store the last used transform. | ||||
| 				} | ||||
| @ -542,9 +555,10 @@ public: | ||||
| 				{ | ||||
| 					xformIndex = NextXformFromIndex(rand.Rand(), lastXformUsed); | ||||
|  | ||||
| 					if (xforms[xformIndex].Apply(&p1, &p1, rand)) | ||||
| 						DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p1, rand); | ||||
| 					if (xforms[xformIndex].Apply(&p1, &p2, rand)) | ||||
| 						DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p2, rand); | ||||
|  | ||||
| 					p1 = p2; | ||||
| 					lastXformUsed = xformIndex + 1;//Store the last used transform. | ||||
| 				} | ||||
|  | ||||
| @ -554,10 +568,11 @@ public: | ||||
| 				{ | ||||
| 					xformIndex = NextXformFromIndex(rand.Rand(), lastXformUsed); | ||||
|  | ||||
| 					if (xforms[xformIndex].Apply(&p1, &p1, rand))//Feed the resulting value of applying the randomly selected xform back into the next iter, and not the result of applying the final xform. | ||||
| 						DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p1, rand); | ||||
| 					if (xforms[xformIndex].Apply(&p1, &p2, rand))//Feed the resulting value of applying the randomly selected xform back into the next iter, and not the result of applying the final xform. | ||||
| 						DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p2, rand); | ||||
|  | ||||
| 					DoFinalXform(ember, p1, samples + i, rand); | ||||
| 					p1 = p2; | ||||
| 					DoFinalXform(ember, p2, samples + i, rand); | ||||
| 					lastXformUsed = xformIndex + 1;//Store the last used transform. | ||||
| 				} | ||||
| 			} | ||||
| @ -569,9 +584,10 @@ public: | ||||
| 				{ | ||||
| 					xformIndex = NextXformFromIndex(rand.Rand(), lastXformUsed); | ||||
|  | ||||
| 					if (xforms[xformIndex].Apply(&p1, &p1, rand)) | ||||
| 						DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p1, rand); | ||||
| 					if (xforms[xformIndex].Apply(&p1, &p2, rand)) | ||||
| 						DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p2, rand); | ||||
|  | ||||
| 					p1 = p2; | ||||
| 					lastXformUsed = xformIndex + 1;//Store the last used transform. | ||||
| 				} | ||||
|  | ||||
|  | ||||
| @ -603,24 +603,24 @@ public: | ||||
| 		outPoint->m_Opacity = m_Opacity; | ||||
| 		iterHelper.m_Color.x = outPoint->m_ColorX = m_ColorSpeedCache + (m_OneMinusColorCache * inPoint->m_ColorX); | ||||
|  | ||||
| 		//Compute the pre affine portion of the transform. | ||||
| 		//These x, y values are what get passed to the variations below. | ||||
| 		//Note that they are not changed after this, except in the case of pre_ variations. | ||||
| 		if (m_HasPre) | ||||
| 		{ | ||||
| 			iterHelper.m_TransX = (m_Affine.A() * inPoint->m_X) + (m_Affine.B() * inPoint->m_Y) + m_Affine.C(); | ||||
| 			iterHelper.m_TransY = (m_Affine.D() * inPoint->m_X) + (m_Affine.E() * inPoint->m_Y) + m_Affine.F(); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			iterHelper.m_TransX = inPoint->m_X; | ||||
| 			iterHelper.m_TransY = inPoint->m_Y; | ||||
| 		} | ||||
|  | ||||
| 		iterHelper.m_TransZ = inPoint->m_Z; | ||||
|  | ||||
| 		if (m_HasPreOrRegularVars) | ||||
| 		{ | ||||
| 			//Compute the pre affine portion of the transform. | ||||
| 			//These x, y values are what get passed to the variations below. | ||||
| 			//Note that they are not changed after this, except in the case of pre_ variations. | ||||
| 			if (m_HasPre) | ||||
| 			{ | ||||
| 				iterHelper.m_TransX = (m_Affine.A() * inPoint->m_X) + (m_Affine.B() * inPoint->m_Y) + m_Affine.C(); | ||||
| 				iterHelper.m_TransY = (m_Affine.D() * inPoint->m_X) + (m_Affine.E() * inPoint->m_Y) + m_Affine.F(); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				iterHelper.m_TransX = inPoint->m_X; | ||||
| 				iterHelper.m_TransY = inPoint->m_Y; | ||||
| 			} | ||||
|  | ||||
| 			iterHelper.m_TransZ = inPoint->m_Z; | ||||
|  | ||||
| 			//Apply pre_ variations, these don't affect outPoint, only iterHelper.m_TransX, Y, Z. | ||||
| 			for (i = 0; i < PreVariationCount(); i++) | ||||
| 			{ | ||||
|  | ||||
| @ -25,10 +25,87 @@ template <typename T> const string& IterOpenCLKernelCreator<T>::ZeroizeEntryPoin | ||||
| template <typename T> const string& IterOpenCLKernelCreator<T>::SumHistKernel() const     { return m_SumHistKernel;     } | ||||
| template <typename T> const string& IterOpenCLKernelCreator<T>::SumHistEntryPoint() const { return m_SumHistEntryPoint; } | ||||
| template <typename T> const string& IterOpenCLKernelCreator<T>::IterEntryPoint() const    { return m_IterEntryPoint;    } | ||||
|  | ||||
| /// <summary> | ||||
| /// Create the iteration kernel string using the Cuburn method. | ||||
| /// Template argument expected to be float or double. | ||||
| /// Pre Reg Post Formula | ||||
| /// x			 trans = affine(inpoint) | ||||
| ///				 foreach prevar | ||||
| ///					tempin = trans | ||||
| ///					tempout = prevar(i, tempin) | ||||
| ///					trans = tempout | ||||
| ///				 outpoint = trans | ||||
| /// | ||||
| /// x	x		 trans = affine(inpoint) | ||||
| ///				 foreach prevar | ||||
| ///					tempin = trans | ||||
| ///					tempout = prevar(i, tempin) | ||||
| ///					trans = tempout | ||||
| ///				 tempin = trans | ||||
| ///				 outpoint = 0 | ||||
| ///				 foreach regvar | ||||
| ///					tempout = regvar(i, tempin) | ||||
| ///					outpoint += tempout | ||||
| // | ||||
| /// x	x	x | ||||
| ///				 trans = affine(inpoint) | ||||
| ///				 foreach prevar | ||||
| ///					tempin = trans | ||||
| ///					tempout = prevar(i, tempin) | ||||
| ///					trans = tempout | ||||
| ///				 tempin = trans | ||||
| ///				 outpoint = 0 | ||||
| ///				 foreach regvar | ||||
| ///					tempout = regvar(i, tempin) | ||||
| ///					outpoint += tempout | ||||
| ///				 foreach postvar | ||||
| ///					tempin = outpoint | ||||
| ///					tempout = postvar(i, tempin) | ||||
| ///					outpoint = tempout | ||||
| /// | ||||
| /// x		x | ||||
| ///				 trans = affine(inpoint) | ||||
| ///				 foreach prevar | ||||
| ///					tempin = trans | ||||
| ///					tempout = prevar(i, tempin) | ||||
| ///					trans = tempout | ||||
| ///				 outpoint = trans | ||||
| ///				 foreach postvar | ||||
| ///					tempin = outpoint | ||||
| ///					tempout = postvar(i, tempin) | ||||
| ///					outpoint = tempout | ||||
| /// | ||||
| ///		x | ||||
| ///				 trans = affine(inpoint) | ||||
| ///				 tempin = trans | ||||
| ///				 outpoint = 0 | ||||
| ///				 foreach regvar | ||||
| ///					tempout = regvar(i, tempin) | ||||
| ///					outpoint += tempout | ||||
| /// | ||||
| ///		x	x | ||||
| ///				 trans = affine(inpoint) | ||||
| ///				 tempin = trans | ||||
| ///				 outpoint = 0 | ||||
| ///				 foreach regvar | ||||
| ///					tempout = regvar(i, tempin) | ||||
| ///					outpoint += tempout | ||||
| ///				 foreach postvar | ||||
| ///					tempin = outpoint | ||||
| ///					tempout = postvar(i, tempin) | ||||
| ///					outpoint = tempout | ||||
| /// | ||||
| ///			x | ||||
| ///				 trans = affine(inpoint) | ||||
| ///				 outpoint = 0 | ||||
| ///				 foreach postvar | ||||
| ///					tempin = outpoint | ||||
| ///					tempout = postvar(i, tempin) | ||||
| ///					outpoint = tempout | ||||
| /// | ||||
| ///	none		 trans = affine(inpoint) | ||||
| ///				 outpoint = 0 | ||||
| /// | ||||
| /// </summary> | ||||
| /// <param name="ember">The ember to create the kernel string for</param> | ||||
| /// <param name="params">The parametric variation #define string</param> | ||||
| @ -59,6 +136,7 @@ string IterOpenCLKernelCreator<T>::CreateIterKernelString(const Ember<T>& ember, | ||||
| 		bool needPrecalcAngles = false; | ||||
| 		bool needPrecalcAtanXY = false; | ||||
| 		bool needPrecalcAtanYX = false; | ||||
| 		bool hasPreReg = (xform->PreVariationCount() + xform->VariationCount()) > 0; | ||||
| 		v = varIndex = varCount = 0; | ||||
| 		xformFuncs << | ||||
| 				   "void Xform" << i << "(__constant XformCL* xform, __constant real_t* parVars, __global real_t* globalShared, Point* inPoint, Point* outPoint, uint2* mwc, VariationState* varState)\n" << | ||||
| @ -96,32 +174,24 @@ string IterOpenCLKernelCreator<T>::CreateIterKernelString(const Ember<T>& ember, | ||||
|  | ||||
| 		xformFuncs << "\treal_t tempColor = outPoint->m_ColorX = fma(xform->m_OneMinusColorCache, inPoint->m_ColorX, xform->m_ColorSpeedCache);\n\n"; | ||||
|  | ||||
| 		if (xform->PreVariationCount() + xform->VariationCount() == 0) | ||||
| 		if (optAffine && xform->m_Affine.IsID()) | ||||
| 		{ | ||||
| 			xformFuncs << | ||||
| 					   "	outPoint->m_X = 0;\n" | ||||
| 					   "	outPoint->m_Y = 0;\n" | ||||
| 					   "	outPoint->m_Z = 0;\n"; | ||||
| 					   "	transX = inPoint->m_X;\n" << | ||||
| 					   "	transY = inPoint->m_Y;\n"; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			if (optAffine && xform->m_Affine.IsID()) | ||||
| 			{ | ||||
| 				xformFuncs << | ||||
| 						   "	transX = inPoint->m_X;\n" << | ||||
| 						   "	transY = inPoint->m_Y;\n"; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				xformFuncs << | ||||
| 						   "	transX = fma(xform->m_A, inPoint->m_X, fma(xform->m_B, inPoint->m_Y, xform->m_C));\n" << | ||||
| 						   "	transY = fma(xform->m_D, inPoint->m_X, fma(xform->m_E, inPoint->m_Y, xform->m_F));\n"; | ||||
| 			} | ||||
|  | ||||
| 			xformFuncs << | ||||
| 					   "	transZ = inPoint->m_Z;\n"; | ||||
| 			varCount = xform->PreVariationCount(); | ||||
| 					   "	transX = fma(xform->m_A, inPoint->m_X, fma(xform->m_B, inPoint->m_Y, xform->m_C));\n" << | ||||
| 					   "	transY = fma(xform->m_D, inPoint->m_X, fma(xform->m_E, inPoint->m_Y, xform->m_F));\n"; | ||||
| 		} | ||||
|  | ||||
| 		xformFuncs << "	transZ = inPoint->m_Z;\n"; | ||||
| 		varCount = xform->PreVariationCount(); | ||||
|  | ||||
| 		if (hasPreReg) | ||||
| 		{ | ||||
| 			if (varCount > 0) | ||||
| 			{ | ||||
| 				xformFuncs << "\n\t//Apply each of the " << varCount << " pre variations in this xform.\n"; | ||||
| @ -186,6 +256,13 @@ string IterOpenCLKernelCreator<T>::CreateIterKernelString(const Ember<T>& ember, | ||||
| 						   "	outPoint->m_Z = transZ;\n"; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			xformFuncs << | ||||
| 					   "	outPoint->m_X = 0;\n" | ||||
| 					   "	outPoint->m_Y = 0;\n" | ||||
| 					   "	outPoint->m_Z = 0;\n"; | ||||
| 		} | ||||
|  | ||||
| 		if (xform->PostVariationCount() > 0) | ||||
| 		{ | ||||
| @ -450,13 +527,6 @@ string IterOpenCLKernelCreator<T>::CreateIterKernelString(const Ember<T>& ember, | ||||
| 		   "\n" | ||||
| 		   //Write to another thread's location. | ||||
| 		   "		swap[sw] = secondPoint;\n"; | ||||
|  | ||||
| 		if (hasVarState) | ||||
| 		{ | ||||
| 			os << | ||||
| 			   "		varStates[blockStartIndex + sw] = varState;\n"; | ||||
| 		} | ||||
|  | ||||
| 		os << | ||||
| 		   "\n" | ||||
| 		   //Populate randomized xform index buffer with new random values. | ||||
| @ -466,13 +536,6 @@ string IterOpenCLKernelCreator<T>::CreateIterKernelString(const Ember<T>& ember, | ||||
| 		   "		barrier(CLK_LOCAL_MEM_FENCE);\n" | ||||
| 		   //Another thread will have written to this thread's location, so read the new value and use it for accumulation below. | ||||
| 		   "		firstPoint = swap[threadIndex];\n"; | ||||
|  | ||||
| 		if (hasVarState) | ||||
| 		{ | ||||
| 			os << | ||||
| 			   "		varState = varStates[blockStartThreadIndex];\n" | ||||
| 			   ; | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @ -488,14 +551,40 @@ string IterOpenCLKernelCreator<T>::CreateIterKernelString(const Ember<T>& ember, | ||||
| 	os << | ||||
| 	   "\n" | ||||
| 	   "		if (fuse)\n" | ||||
| 	   "		{\n" | ||||
| 	   "		{\n"; | ||||
|  | ||||
| 	if (hasVarState && ember.XformCount() > 1) | ||||
| 	{ | ||||
| 		os << | ||||
| 		   "			varStates[blockStartIndex + sw] = varState;\n\n"; | ||||
| 	} | ||||
|  | ||||
| 	os << | ||||
| 	   "			if (i >= fuseCount - 1)\n" | ||||
| 	   "			{\n" | ||||
| 	   "				i = 0;\n" | ||||
| 	   "				fuse = false;\n" | ||||
| 	   "				itersToDo = iterCount;\n" | ||||
| 	   "				barrier(CLK_LOCAL_MEM_FENCE);\n"//Sort of seems necessary, sort of doesn't. Makes no speed difference. | ||||
| 	   "				itersToDo = iterCount;\n"; | ||||
|  | ||||
| 	if (ember.XformCount() > 1) | ||||
| 		os << | ||||
| 		   "				barrier(CLK_LOCAL_MEM_FENCE);\n"//Sort of seems necessary, sort of doesn't. Makes no speed difference. | ||||
| 		   ; | ||||
|  | ||||
| 	os << | ||||
| 	   "			}\n" | ||||
| 	   ; | ||||
|  | ||||
| 	if (hasVarState && ember.XformCount() > 1) | ||||
| 	{ | ||||
| 		os << | ||||
| 		   "\n" | ||||
| 		   "			barrier(CLK_GLOBAL_MEM_FENCE);\n"//Sort of seems necessary, sort of doesn't. Makes no speed difference. | ||||
| 		   "			varState = varStates[blockStartThreadIndex];" | ||||
| 		   ; | ||||
| 	} | ||||
|  | ||||
| 	os << | ||||
| 	   "\n" | ||||
| 	   "			continue;\n" | ||||
| 	   "		}\n" | ||||
| @ -516,6 +605,13 @@ string IterOpenCLKernelCreator<T>::CreateIterKernelString(const Ember<T>& ember, | ||||
| 		   "\n"; | ||||
| 	} | ||||
|  | ||||
| 	if (hasVarState && ember.XformCount() > 1) | ||||
| 	{ | ||||
| 		os << | ||||
| 		   "		varStates[blockStartIndex + sw] = varState;\n" | ||||
| 		   ; | ||||
| 	} | ||||
|  | ||||
| 	os << CreateProjectionString(ember); | ||||
|  | ||||
| 	if (doAccum) | ||||
| @ -591,8 +687,16 @@ string IterOpenCLKernelCreator<T>::CreateIterKernelString(const Ember<T>& ember, | ||||
| 		os << | ||||
| 		   "			}\n"//histIndex < histSize. | ||||
| 		   "		}\n"//CarToRasInBounds. | ||||
| 		   "\n" | ||||
| 		   "\n"; | ||||
| 		os << | ||||
| 		   "		barrier(CLK_GLOBAL_MEM_FENCE);\n";//Barrier every time, whether or not the point was in bounds, else artifacts will occur when doing strips. | ||||
|  | ||||
| 		if (hasVarState && ember.XformCount() > 1) | ||||
| 		{ | ||||
| 			os << | ||||
| 			   "		varState = varStates[blockStartThreadIndex];\n" | ||||
| 			   ; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	os << | ||||
| @ -610,7 +714,7 @@ string IterOpenCLKernelCreator<T>::CreateIterKernelString(const Ember<T>& ember, | ||||
| 	   "	seeds[pointsIndex] = mwc;\n" | ||||
| 	   "	points[blockStartThreadIndex] = firstPoint;\n"; | ||||
|  | ||||
| 	if (hasVarState) | ||||
| 	if (hasVarState && ember.XformCount() == 1) | ||||
| 	{ | ||||
| 		os << | ||||
| 		   "	varStates[blockStartThreadIndex] = varState;\n"; | ||||
|  | ||||
| @ -58,7 +58,7 @@ | ||||
|     <enum>QFrame::NoFrame</enum> | ||||
|    </property> | ||||
|    <property name="text"> | ||||
|     <string><html><head/><body><p align="center"><span style=" font-size:10pt;">Fractorium 1.0.0.18</span></p><p align="center"><span style=" font-size:10pt;">A Qt-based fractal flame editor which uses a C++ re-write of the flam3 algorithm named Ember and a GPU capable version named EmberCL which implements a portion of the cuburn algorithm in OpenCL.</span></p><p align="center"><a href="http://fractorium.com"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">fractorium.com</span></a></p></body></html></string> | ||||
|     <string><html><head/><body><p align="center"><span style=" font-size:10pt;">Fractorium 1.0.0.19</span></p><p align="center"><span style=" font-size:10pt;">A Qt-based fractal flame editor which uses a C++ re-write of the flam3 algorithm named Ember and a GPU capable version named EmberCL which implements a portion of the cuburn algorithm in OpenCL.</span></p><p align="center"><a href="http://fractorium.com"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">fractorium.com</span></a></p></body></html></string> | ||||
|    </property> | ||||
|    <property name="textFormat"> | ||||
|     <enum>Qt::RichText</enum> | ||||
|  | ||||
| @ -139,6 +139,7 @@ public slots: | ||||
| 	void OnActionNewEmptyFlameInCurrentFile(bool checked); | ||||
| 	void OnActionNewRandomFlameInCurrentFile(bool checked); | ||||
| 	void OnActionCopyFlameInCurrentFile(bool checked); | ||||
| 	void OnActionCreateReferenceFile(bool checked); | ||||
| 	void OnActionOpen(bool checked); | ||||
| 	void OnActionSaveCurrentAsXml(bool checked); | ||||
| 	void OnActionSaveEntireFileAsXml(bool checked); | ||||
|  | ||||
| @ -96,6 +96,7 @@ public: | ||||
| 	virtual void NewEmptyFlameInCurrentFile() { } | ||||
| 	virtual void NewRandomFlameInCurrentFile() { } | ||||
| 	virtual void CopyFlameInCurrentFile() { } | ||||
| 	virtual void CreateReferenceFile() { } | ||||
| 	virtual void OpenAndPrepFiles(const QStringList& filenames, bool append) { } | ||||
| 	virtual void SaveCurrentAsXml() { } | ||||
| 	virtual void SaveEntireFileAsXml() { } | ||||
| @ -384,6 +385,7 @@ public: | ||||
| 	virtual void NewEmptyFlameInCurrentFile() override; | ||||
| 	virtual void NewRandomFlameInCurrentFile() override; | ||||
| 	virtual void CopyFlameInCurrentFile() override; | ||||
| 	virtual void CreateReferenceFile() override; | ||||
| 	virtual void OpenAndPrepFiles(const QStringList& filenames, bool append) override; | ||||
| 	virtual void SaveCurrentAsXml() override; | ||||
| 	virtual void SaveEntireFileAsXml() override; | ||||
|  | ||||
| @ -11,6 +11,7 @@ void Fractorium::InitMenusUI() | ||||
| 	connect(ui.ActionNewEmptyFlameInCurrentFile,  SIGNAL(triggered(bool)), this, SLOT(OnActionNewEmptyFlameInCurrentFile(bool)),  Qt::QueuedConnection); | ||||
| 	connect(ui.ActionNewRandomFlameInCurrentFile, SIGNAL(triggered(bool)), this, SLOT(OnActionNewRandomFlameInCurrentFile(bool)), Qt::QueuedConnection); | ||||
| 	connect(ui.ActionCopyFlameInCurrentFile,	  SIGNAL(triggered(bool)), this, SLOT(OnActionCopyFlameInCurrentFile(bool)),	  Qt::QueuedConnection); | ||||
| 	connect(ui.ActionCreateReferenceFile,         SIGNAL(triggered(bool)), this, SLOT(OnActionCreateReferenceFile(bool)),         Qt::QueuedConnection); | ||||
| 	connect(ui.ActionOpen,						  SIGNAL(triggered(bool)), this, SLOT(OnActionOpen(bool)),						  Qt::QueuedConnection); | ||||
| 	connect(ui.ActionSaveCurrentAsXml,			  SIGNAL(triggered(bool)), this, SLOT(OnActionSaveCurrentAsXml(bool)),			  Qt::QueuedConnection); | ||||
| 	connect(ui.ActionSaveEntireFileAsXml,		  SIGNAL(triggered(bool)), this, SLOT(OnActionSaveEntireFileAsXml(bool)),		  Qt::QueuedConnection); | ||||
| @ -172,6 +173,104 @@ void FractoriumEmberController<T>::CopyFlameInCurrentFile() | ||||
|  | ||||
| void Fractorium::OnActionCopyFlameInCurrentFile(bool checked) { m_Controller->CopyFlameInCurrentFile(); } | ||||
|  | ||||
| /// <summary> | ||||
| /// Create a reference file containing one ember for every possible regular variation, plus one for post_smartcrop | ||||
| /// since it only exists in post form. | ||||
| /// This will replace whatever file the user has open. | ||||
| /// Clears the undo state. | ||||
| /// Resets the rendering process. | ||||
| /// </summary> | ||||
| template <typename T> | ||||
| void FractoriumEmberController<T>::CreateReferenceFile() | ||||
| { | ||||
| 	bool nv = false; | ||||
| 	size_t i; | ||||
| 	StopAllPreviewRenderers(); | ||||
| 	auto temppal = m_Ember.m_Palette; | ||||
| 	m_EmberFile.Clear(); | ||||
| 	m_EmberFile.m_Filename = QString("Reference_") + EMBER_VERSION; | ||||
| 	auto varList = VariationList<T>::Instance(); | ||||
| 	auto& regVars = varList->RegVars(); | ||||
| 	auto count = regVars.size(); | ||||
| 	auto addsquaresfunc = [&](size_t i, const Variation<T>* var) | ||||
| 	{ | ||||
| 		Ember<T> ember; | ||||
| 		Xform<T> xf0, xf1, xf2, xf3, xf4, xffinal; | ||||
| 		// | ||||
| 		xf0.AddVariation(varList->GetVariationCopy(eVariationId::VAR_SQUARE, T(0.5))); | ||||
| 		// | ||||
| 		xf1.m_Affine.C(T(0.5)); | ||||
| 		xf1.m_Affine.F(T(0.5)); | ||||
| 		xf1.AddVariation(varList->GetVariationCopy(eVariationId::VAR_LINEAR)); | ||||
| 		// | ||||
| 		xf2.m_Affine.C(T(-0.5)); | ||||
| 		xf2.m_Affine.F(T(0.5)); | ||||
| 		xf2.AddVariation(varList->GetVariationCopy(eVariationId::VAR_LINEAR)); | ||||
| 		// | ||||
| 		xf3.m_Affine.C(T(-0.5)); | ||||
| 		xf3.m_Affine.F(T(-0.5)); | ||||
| 		xf3.AddVariation(varList->GetVariationCopy(eVariationId::VAR_LINEAR)); | ||||
| 		// | ||||
| 		xf4.m_Affine.C(T(0.5)); | ||||
| 		xf4.m_Affine.F(T(-0.5)); | ||||
| 		xf4.AddVariation(varList->GetVariationCopy(eVariationId::VAR_LINEAR)); | ||||
| 		// | ||||
| 		xffinal.AddVariation(var->Copy()); | ||||
| 		// | ||||
| 		ember.AddXform(xf0); | ||||
| 		ember.AddXform(xf1); | ||||
| 		ember.AddXform(xf2); | ||||
| 		ember.AddXform(xf3); | ||||
| 		ember.AddXform(xf4); | ||||
| 		ember.SetFinalXform(xffinal); | ||||
| 		ember.EqualizeWeights(); | ||||
| 		ember.m_Index = i; | ||||
| 		ember.m_MaxRadDE = 0; | ||||
| 		ember.m_Name = var->Name() + " Squares"; | ||||
| 		ember.m_Palette = temppal; | ||||
| 		m_EmberFile.m_Embers.push_back(ember); | ||||
| 	}; | ||||
| 	auto addsbarsfunc = [&](size_t i, const Variation<T>* var) | ||||
| 	{ | ||||
| 		Ember<T> ember; | ||||
| 		Xform<T> xf0, xf1, xf2, xffinal; | ||||
| 		// | ||||
| 		xf0.AddVariation(varList->GetVariationCopy(eVariationId::VAR_PRE_BLUR, T(100))); | ||||
| 		xf0.AddVariation(varList->GetVariationCopy(eVariationId::VAR_CYLINDER, T(0.1))); | ||||
| 		// | ||||
| 		xf1.m_Affine.C(T(0.4)); | ||||
| 		xf1.AddVariation(varList->GetVariationCopy(eVariationId::VAR_LINEAR)); | ||||
| 		// | ||||
| 		xf2.m_Affine.C(T(-0.4)); | ||||
| 		xf2.AddVariation(varList->GetVariationCopy(eVariationId::VAR_LINEAR)); | ||||
| 		// | ||||
| 		xffinal.AddVariation(var->Copy()); | ||||
| 		ember.AddXform(xf0); | ||||
| 		ember.AddXform(xf1); | ||||
| 		ember.AddXform(xf2); | ||||
| 		ember.SetFinalXform(xffinal); | ||||
| 		ember.EqualizeWeights(); | ||||
| 		ember.m_Index = i; | ||||
| 		ember.m_MaxRadDE = 0; | ||||
| 		ember.m_Name = var->Name() + " Bars"; | ||||
| 		ember.m_Palette = temppal; | ||||
| 		m_EmberFile.m_Embers.push_back(ember); | ||||
| 	}; | ||||
|  | ||||
| 	for (i = 0; i < count; i++) | ||||
| 	{ | ||||
| 		addsquaresfunc(i, regVars[i]); | ||||
| 		addsbarsfunc(i, regVars[i]); | ||||
| 	} | ||||
|  | ||||
| 	addsquaresfunc(i, varList->GetVariation(eVariationId::VAR_POST_SMARTCROP));//post_smartcrop is the only variation that exists only in post form, so it must be done manually here. | ||||
| 	addsbarsfunc(i, varList->GetVariation(eVariationId::VAR_POST_SMARTCROP)); | ||||
| 	m_LastSaveAll = ""; | ||||
| 	FillLibraryTree(); | ||||
| } | ||||
|  | ||||
| void Fractorium::OnActionCreateReferenceFile(bool checked) { m_Controller->CreateReferenceFile(); } | ||||
|  | ||||
| /// <summary> | ||||
| /// Open a list of ember Xml files, apply various values from the GUI widgets. | ||||
| /// Either append these newly read embers to the existing open embers, | ||||
|  | ||||
| @ -36,7 +36,7 @@ void Fractorium::InitXformsUI() | ||||
| 	ui.CurrentXformCombo->view()->setMinimumWidth(100); | ||||
| 	ui.CurrentXformCombo->view()->setMaximumWidth(500); | ||||
| 	//ui.CurrentXformCombo->view()->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); | ||||
| 	ui.CurrentXformCombo->view()->setSizeAdjustPolicy(QAbstractScrollArea::SizeAdjustPolicy::AdjustToContentsOnFirstShow); | ||||
| 	ui.CurrentXformCombo->view()->setSizeAdjustPolicy(QAbstractScrollArea::SizeAdjustPolicy::AdjustToContents); | ||||
| #ifndef _WIN32 | ||||
| 	//For some reason linux makes these 24x24, even though the designer explicitly says 16x16. | ||||
| 	ui.AddXformButton->setIconSize(QSize(16, 16)); | ||||
| @ -518,9 +518,9 @@ void FractoriumEmberController<T>::FillWithXform(Xform<T>* xform) | ||||
|  | ||||
| 	if (auto item = m_Fractorium->ui.XformWeightNameTable->item(0, 1)) | ||||
| 	{ | ||||
| 		m_Fractorium->ui.XformWeightNameTable->blockSignals(true); | ||||
| 		item->setText(QString::fromStdString(xform->m_Name)); | ||||
| 		m_Fractorium->ui.XformWeightNameTable->blockSignals(false); | ||||
| 		m_Fractorium->m_XformNameEdit->blockSignals(true); | ||||
| 		m_Fractorium->m_XformNameEdit->setText(QString::fromStdString(xform->m_Name)); | ||||
| 		m_Fractorium->m_XformNameEdit->blockSignals(false); | ||||
| 	} | ||||
|  | ||||
| 	FillVariationTreeWithXform(xform); | ||||
| @ -656,7 +656,7 @@ void FractoriumEmberController<T>::UpdateXformName(int index) | ||||
| 		auto view = m_Fractorium->ui.CurrentXformCombo->view(); | ||||
| 		auto fontMetrics1 = view->fontMetrics(); | ||||
| 		auto textWidth = m_Fractorium->ui.CurrentXformCombo->width(); | ||||
| 		auto ww = fontMetrics1.width("WW"); | ||||
| 		auto ww = fontMetrics1.width("WW") * 3; | ||||
|  | ||||
| 		for (int i = 0; i < m_Fractorium->ui.CurrentXformCombo->count(); ++i) | ||||
| 			textWidth = std::max(fontMetrics1.width(m_Fractorium->ui.CurrentXformCombo->itemText(i)) + ww, textWidth); | ||||
|  | ||||
| @ -433,7 +433,7 @@ void PaletteEditor::OnCopyPaletteFileButtonClicked() | ||||
| /// </summary> | ||||
| void PaletteEditor::OnAppendPaletteButtonClicked() | ||||
| { | ||||
| 	auto& pal = m_GradientColorView->GetPalette(256); | ||||
| 	auto& pal = GetPalette(256); | ||||
| 	m_PaletteList->AddPaletteToFile(m_CurrentPaletteFilePath, pal); | ||||
| 	::FillPaletteTable(m_CurrentPaletteFilePath, ui->PaletteListTable, m_PaletteList); | ||||
| 	m_PaletteIndex = ui->PaletteListTable->rowCount() - 1; | ||||
| @ -446,7 +446,7 @@ void PaletteEditor::OnAppendPaletteButtonClicked() | ||||
| /// </summary> | ||||
| void PaletteEditor::OnOverwritePaletteButtonClicked() | ||||
| { | ||||
| 	auto& pal = m_GradientColorView->GetPalette(256); | ||||
| 	auto& pal = GetPalette(256); | ||||
| 	m_PaletteList->Replace(m_CurrentPaletteFilePath, pal, m_PaletteIndex); | ||||
| 	::FillPaletteTable(m_CurrentPaletteFilePath, ui->PaletteListTable, m_PaletteList); | ||||
| 	emit PaletteFileChanged(); | ||||
| @ -632,10 +632,11 @@ void PaletteEditor::EnablePaletteFileControls() | ||||
| void PaletteEditor::EnablePaletteControls() | ||||
| { | ||||
| 	bool b = IsCurrentPaletteAndFileEditable();//Both the file and the current palette must be editable. | ||||
| 	auto& pal = GetPalette(256); | ||||
| 	ui->DeletePaletteButton->setEnabled(b); | ||||
| 	ui->CopyPaletteFileButton->setEnabled(b); | ||||
| 	ui->AppendPaletteButton->setEnabled(b); | ||||
| 	ui->OverwritePaletteButton->setEnabled(b && (GetFilename(m_CurrentPaletteFilePath) == GetFilename(*m_GradientColorView->GetPalette(256).m_Filename.get())));//Only allow overwrite if the palette is from the file it's overwriting a palette in. | ||||
| 	ui->OverwritePaletteButton->setEnabled(b && pal.m_Filename.get() && (GetFilename(m_CurrentPaletteFilePath) == GetFilename(*pal.m_Filename.get())));//Only allow overwrite if the palette is from the file it's overwriting a palette in. | ||||
| 	ui->AddColorButton->setEnabled(b); | ||||
| 	ui->DistributeColorsButton->setEnabled(b); | ||||
| 	ui->AutoDistributeCheckBox->setEnabled(b); | ||||
| @ -654,5 +655,5 @@ void PaletteEditor::EnablePaletteControls() | ||||
| /// <returns>True if both the currently selected palette is editable and if all palettes in the currently selected file are editable.</returns> | ||||
| bool PaletteEditor::IsCurrentPaletteAndFileEditable() | ||||
| { | ||||
| 	return m_PaletteList->IsModifiable(m_CurrentPaletteFilePath) && !m_GradientColorView->GetPalette(256).m_SourceColors.empty(); | ||||
| 	return m_PaletteList->IsModifiable(m_CurrentPaletteFilePath) && !GetPalette(256).m_SourceColors.empty(); | ||||
| } | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| using System.Reflection; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Runtime.InteropServices; | ||||
|  | ||||
| // General Information about an assembly is controlled through the following | ||||
| @ -10,7 +9,7 @@ using System.Runtime.InteropServices; | ||||
| [assembly: AssemblyConfiguration("")] | ||||
| [assembly: AssemblyCompany("")] | ||||
| [assembly: AssemblyProduct("apoconv")] | ||||
| [assembly: AssemblyCopyright("Copyright ©  2019")] | ||||
| [assembly: AssemblyCopyright("Copyright © 2020")] | ||||
| [assembly: AssemblyTrademark("")] | ||||
| [assembly: AssemblyCulture("")] | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Person
					Person