diff --git a/Builds/MSVC/Installer/Product.wxs b/Builds/MSVC/Installer/Product.wxs index 2782a52..c317489 100644 --- a/Builds/MSVC/Installer/Product.wxs +++ b/Builds/MSVC/Installer/Product.wxs @@ -1,6 +1,6 @@ - + @@ -13,7 +13,7 @@ - + ::epsilon()//Apoplugin.h uses -20, but it's more mathematically correct to do it this way. diff --git a/Source/Ember/Iterator.h b/Source/Ember/Iterator.h index b136ab4..490a33a 100644 --- a/Source/Ember/Iterator.h +++ b/Source/Ember/Iterator.h @@ -300,7 +300,7 @@ public: virtual size_t Iterate(Ember& ember, const IterParams params, const CarToRas& ctr, Point* samples, QTIsaac& rand) override { size_t i, badVals = 0; - Point tempPoint, p1; + Point 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 tempPoint, p1; + Point 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. } diff --git a/Source/Ember/Xform.h b/Source/Ember/Xform.h index 3b12db0..d5ac347 100644 --- a/Source/Ember/Xform.h +++ b/Source/Ember/Xform.h @@ -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++) { diff --git a/Source/EmberCL/IterOpenCLKernelCreator.cpp b/Source/EmberCL/IterOpenCLKernelCreator.cpp index dceb59f..9c92714 100644 --- a/Source/EmberCL/IterOpenCLKernelCreator.cpp +++ b/Source/EmberCL/IterOpenCLKernelCreator.cpp @@ -25,10 +25,87 @@ template const string& IterOpenCLKernelCreator::ZeroizeEntryPoin template const string& IterOpenCLKernelCreator::SumHistKernel() const { return m_SumHistKernel; } template const string& IterOpenCLKernelCreator::SumHistEntryPoint() const { return m_SumHistEntryPoint; } template const string& IterOpenCLKernelCreator::IterEntryPoint() const { return m_IterEntryPoint; } - /// /// 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 +/// /// /// The ember to create the kernel string for /// The parametric variation #define string @@ -59,6 +136,7 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& 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::CreateIterKernelString(const Ember& 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::CreateIterKernelString(const Ember& 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::CreateIterKernelString(const Ember& 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::CreateIterKernelString(const Ember& 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::CreateIterKernelString(const Ember& 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::CreateIterKernelString(const Ember& ember, "\n"; } + if (hasVarState && ember.XformCount() > 1) + { + os << + " varStates[blockStartIndex + sw] = varState;\n" + ; + } + os << CreateProjectionString(ember); if (doAccum) @@ -591,8 +687,16 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& 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::CreateIterKernelString(const Ember& ember, " seeds[pointsIndex] = mwc;\n" " points[blockStartThreadIndex] = firstPoint;\n"; - if (hasVarState) + if (hasVarState && ember.XformCount() == 1) { os << " varStates[blockStartThreadIndex] = varState;\n"; diff --git a/Source/Fractorium/AboutDialog.ui b/Source/Fractorium/AboutDialog.ui index d0b1f49..9cb0683 100644 --- a/Source/Fractorium/AboutDialog.ui +++ b/Source/Fractorium/AboutDialog.ui @@ -58,7 +58,7 @@ QFrame::NoFrame - <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> + <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> Qt::RichText diff --git a/Source/Fractorium/Fractorium.h b/Source/Fractorium/Fractorium.h index 5117e44..65b5235 100644 --- a/Source/Fractorium/Fractorium.h +++ b/Source/Fractorium/Fractorium.h @@ -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); diff --git a/Source/Fractorium/FractoriumEmberController.h b/Source/Fractorium/FractoriumEmberController.h index a67f816..f396845 100644 --- a/Source/Fractorium/FractoriumEmberController.h +++ b/Source/Fractorium/FractoriumEmberController.h @@ -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; diff --git a/Source/Fractorium/FractoriumMenus.cpp b/Source/Fractorium/FractoriumMenus.cpp index 2819425..31371f8 100644 --- a/Source/Fractorium/FractoriumMenus.cpp +++ b/Source/Fractorium/FractoriumMenus.cpp @@ -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::CopyFlameInCurrentFile() void Fractorium::OnActionCopyFlameInCurrentFile(bool checked) { m_Controller->CopyFlameInCurrentFile(); } +/// +/// 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. +/// +template +void FractoriumEmberController::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::Instance(); + auto& regVars = varList->RegVars(); + auto count = regVars.size(); + auto addsquaresfunc = [&](size_t i, const Variation* var) + { + Ember ember; + Xform 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* var) + { + Ember ember; + Xform 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(); } + /// /// 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, diff --git a/Source/Fractorium/FractoriumXforms.cpp b/Source/Fractorium/FractoriumXforms.cpp index 7477162..705b310 100644 --- a/Source/Fractorium/FractoriumXforms.cpp +++ b/Source/Fractorium/FractoriumXforms.cpp @@ -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::FillWithXform(Xform* 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::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); diff --git a/Source/Fractorium/PaletteEditor/PaletteEditor.cpp b/Source/Fractorium/PaletteEditor/PaletteEditor.cpp index 8f72943..fc3f3a1 100644 --- a/Source/Fractorium/PaletteEditor/PaletteEditor.cpp +++ b/Source/Fractorium/PaletteEditor/PaletteEditor.cpp @@ -433,7 +433,7 @@ void PaletteEditor::OnCopyPaletteFileButtonClicked() /// 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() /// 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() /// True if both the currently selected palette is editable and if all palettes in the currently selected file are editable. 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(); } diff --git a/Source/apoconv/Properties/AssemblyInfo.cs b/Source/apoconv/Properties/AssemblyInfo.cs index 3e6c45f..620e366 100644 --- a/Source/apoconv/Properties/AssemblyInfo.cs +++ b/Source/apoconv/Properties/AssemblyInfo.cs @@ -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("")]