From 77515aae7344085387497acf8bee84755632f053 Mon Sep 17 00:00:00 2001 From: Person Date: Tue, 23 Apr 2019 19:50:42 -0700 Subject: [PATCH] --User changes -Clear all color curves when clicking Reset while holding down Ctrl. --Code changes -No longer assume palettes are 256 elements. Can now read and write longer palettes. -Ensure OpenCL images always get written when created. --- Source/Ember/EmberDefines.h | 1 - Source/Ember/EmberToXml.cpp | 7 +-- Source/Ember/Palette.h | 17 +++--- Source/Ember/Renderer.cpp | 11 ++-- Source/Ember/XmlToEmber.cpp | 53 +++++++++---------- Source/EmberCL/EmberCLStructs.h | 6 ++- Source/EmberCL/FunctionMapper.cpp | 8 +-- Source/EmberCL/IterOpenCLKernelCreator.cpp | 15 +++--- Source/EmberCL/OpenCLWrapper.cpp | 34 +++++------- Source/EmberCL/RendererCL.cpp | 6 ++- Source/Fractorium/FractoriumEmberController.h | 2 + Source/Fractorium/FractoriumPalette.cpp | 44 +++++++++------ Source/Fractorium/FractoriumParams.cpp | 10 ++-- Source/Fractorium/FractoriumXformsColor.cpp | 2 +- 14 files changed, 115 insertions(+), 101 deletions(-) diff --git a/Source/Ember/EmberDefines.h b/Source/Ember/EmberDefines.h index 45a933e..38bec6e 100644 --- a/Source/Ember/EmberDefines.h +++ b/Source/Ember/EmberDefines.h @@ -53,7 +53,6 @@ namespace EmberNs #define SQRT5 T(2.2360679774997896964091736687313) #define M_PHI T(1.61803398874989484820458683436563) #define COLORMAP_LENGTH 256//These will need to change if 2D palette support is ever added, or variable sized palettes. -#define COLORMAP_LENGTH_MINUS_1 255 #define WHITE 255 #define DEFAULT_SBS (1024 * 10) //#define XC(c) ((const xmlChar*)(c)) diff --git a/Source/Ember/EmberToXml.cpp b/Source/Ember/EmberToXml.cpp index cb8d640..22ffc28 100644 --- a/Source/Ember/EmberToXml.cpp +++ b/Source/Ember/EmberToXml.cpp @@ -259,7 +259,7 @@ string EmberToXml::ToString(Ember& ember, const string& extraAttributes, s //less error prone to just embed the palette. if (hexPalette) { - os << " ::ToString(Ember& ember, const string& extraAttributes, s os << ">\n"; os << std::uppercase; + auto rows = ember.m_Palette.Size() / 8; - for (i = 0; i < 32; i++) + for (i = 0; i < rows; i++) { os << " "; @@ -300,7 +301,7 @@ string EmberToXml::ToString(Ember& ember, const string& extraAttributes, s } else { - for (i = 0; i < 256; i++) + for (i = 0; i < ember.m_Palette.Size(); i++) { double r = ember.m_Palette[i][0] * 255; double g = ember.m_Palette[i][1] * 255; diff --git a/Source/Ember/Palette.h b/Source/Ember/Palette.h index 5af747a..5d37307 100644 --- a/Source/Ember/Palette.h +++ b/Source/Ember/Palette.h @@ -246,7 +246,7 @@ public: for (size_t i = 0; i < Size(); i++) { - size_t ii = (i * 256) / COLORMAP_LENGTH; + size_t ii = (i * Size()) / Size(); T rgb[3], hsv[3]; rgb[0] = m_Entries[ii].r; rgb[1] = m_Entries[ii].g; @@ -279,6 +279,7 @@ public: void MakeAdjustedPalette(Palette& palette, int rot, T hue, T sat, T bright, T cont, uint blur, uint freq) { T rgb[3], hsv[3]; + palette.m_Entries.resize(Size()); if (freq > 1) { @@ -306,13 +307,13 @@ public: } auto tempPal = palette; + intmax_t iSize = intmax_t(Size()); - for (size_t i = 0; i < Size(); i++) + for (intmax_t i = 0; i < iSize; i++) { - int ii = int(i); - rgb[0] = tempPal[std::abs(COLORMAP_LENGTH + ii - rot) % COLORMAP_LENGTH].r;//Rotation. - rgb[1] = tempPal[std::abs(COLORMAP_LENGTH + ii - rot) % COLORMAP_LENGTH].g; - rgb[2] = tempPal[std::abs(COLORMAP_LENGTH + ii - rot) % COLORMAP_LENGTH].b; + rgb[0] = tempPal[std::abs(iSize + i - rot) % iSize].r;//Rotation. + rgb[1] = tempPal[std::abs(iSize + i - rot) % iSize].g; + rgb[2] = tempPal[std::abs(iSize + i - rot) % iSize].b; RgbToHsv(rgb, hsv); hsv[0] += hue * T(6.0);//Hue. hsv[1] = Clamp(hsv[1] + sat, 0, 1);//Saturation. @@ -335,7 +336,7 @@ public: { tempPal = palette; - for (int i = 0; i < 256; i++) + for (int i = 0; i < iSize; i++) { int n = -1; rgb[0] = 0; @@ -345,7 +346,7 @@ public: for (int j = i - int(blur); j <= i + int(blur); j++) { n++; - int k = (256 + j) % 256; + auto k = (iSize + j) % iSize; if (k != i) { diff --git a/Source/Ember/Renderer.cpp b/Source/Ember/Renderer.cpp index 2467b3e..05ae646 100644 --- a/Source/Ember/Renderer.cpp +++ b/Source/Ember/Renderer.cpp @@ -1497,6 +1497,7 @@ void Renderer::Accumulate(QTIsaac& rand, Poin { size_t histIndex, intColorIndex, histSize = m_HistBuckets.size(); bucketT colorIndex, colorIndexFrac; + auto psm1 = m_Ember.m_Palette.Size() - 1; //Linear is a linear scale for when the color index is not a whole number, which is most of the time. //It uses a portion of the value of the index, and the remainder of the next index. @@ -1506,6 +1507,8 @@ void Renderer::Accumulate(QTIsaac& rand, Poin //Use overloaded addition and multiplication operators in vec4 to perform the accumulation. if (PaletteMode() == ePaletteMode::PALETTE_LINEAR) { + auto psm2 = psm1 - 1; + //It's critical to understand what's going on here as it's one of the most important parts of the algorithm. //A color value gets retrieved from the palette and //its RGB values are added to the existing RGB values in the histogram bucket. @@ -1542,7 +1545,7 @@ void Renderer::Accumulate(QTIsaac& rand, Poin //This will result in a few points at the very edges getting discarded, but prevents a crash and doesn't seem to make a speed difference. if (histIndex < histSize) { - colorIndex = bucketT(p.m_ColorX) * COLORMAP_LENGTH_MINUS_1; + colorIndex = bucketT(p.m_ColorX) * psm1; intColorIndex = size_t(colorIndex); if (intColorIndex < 0) @@ -1550,9 +1553,9 @@ void Renderer::Accumulate(QTIsaac& rand, Poin intColorIndex = 0; colorIndexFrac = 0; } - else if (intColorIndex >= COLORMAP_LENGTH_MINUS_1) + else if (intColorIndex >= psm1) { - intColorIndex = COLORMAP_LENGTH_MINUS_1 - 1; + intColorIndex = psm2; colorIndexFrac = 1; } else @@ -1608,7 +1611,7 @@ void Renderer::Accumulate(QTIsaac& rand, Poin if (histIndex < histSize) { - intColorIndex = Clamp(size_t(p.m_ColorX * COLORMAP_LENGTH_MINUS_1), 0, COLORMAP_LENGTH_MINUS_1); + intColorIndex = Clamp(size_t(p.m_ColorX * psm1), 0, psm1); bucketT* __restrict hist = glm::value_ptr(m_HistBuckets[histIndex]);//Vectorizer can't tell these point to different locations. const bucketT* __restrict pal = glm::value_ptr(palette->m_Entries[intColorIndex]); diff --git a/Source/Ember/XmlToEmber.cpp b/Source/Ember/XmlToEmber.cpp index 03d5e57..4ad1f68 100644 --- a/Source/Ember/XmlToEmber.cpp +++ b/Source/Ember/XmlToEmber.cpp @@ -1310,19 +1310,18 @@ bool XmlToEmber::ParseEmberElementFromChaos(xmlNode* emberNode, Ember& cur { if (auto palettevalsnode = GetChildNodeByNodeName(palettenode, "values")) { - int i = 0; float r = 0, g = 0, b = 0; auto colors = CCX(palettevalsnode->children->content); istringstream istr(colors); + currentEmber.m_Palette.m_Entries.clear(); + std::vector tempv; + tempv.reserve(256); - while (istr >> r && istr >> g && istr >> b && i < COLORMAP_LENGTH) - { - currentEmber.m_Palette.m_Entries[i][0] = r; - currentEmber.m_Palette.m_Entries[i][1] = g; - currentEmber.m_Palette.m_Entries[i][2] = b; - currentEmber.m_Palette.m_Entries[i][3] = 1; - i++; - } + while (istr >> r && istr >> g && istr >> b) + tempv.push_back(v4F(r, g, b, 1)); + + if (!tempv.empty()) + currentEmber.m_Palette.m_Entries = std::move(tempv); } } else @@ -1393,9 +1392,10 @@ bool XmlToEmber::ParseEmberElementFromChaos(xmlNode* emberNode, Ember& cur Spline hspline(hvec); Spline sspline(svec); Spline vspline(vvec); - auto stepsize = (1.0f / (COLORMAP_LENGTH - 1)); + currentEmber.m_Palette.m_Entries.resize(COLORMAP_LENGTH); + auto stepsize = (1.0f / (currentEmber.m_Palette.Size() - 1)); - for (auto palindex = 0; palindex < COLORMAP_LENGTH; palindex++) + for (auto palindex = 0; palindex < currentEmber.m_Palette.Size(); palindex++) { float t = palindex * stepsize; auto h = hspline.Interpolate(t); @@ -1768,22 +1768,15 @@ bool XmlToEmber::ParseEmberElement(xmlNode* emberNode, Ember& currentEmber xmlFree(attStr); } - //Palette colors are [0..255], convert to [0..1]. - if (index >= 0 && index <= 255) - { - float alphaPercent = a / 255.0f;//Aplha percentage in the range of 0 to 1. - //Premultiply the palette. - currentEmber.m_Palette.m_Entries[index].r = alphaPercent * (r / 255.0f); - currentEmber.m_Palette.m_Entries[index].g = alphaPercent * (g / 255.0f); - currentEmber.m_Palette.m_Entries[index].b = alphaPercent * (b / 255.0f); - currentEmber.m_Palette.m_Entries[index].a = a / 255.0f;//Will be one for RGB, and other than one if RGBA with A != 255. - } - else - { - stringstream ss; - ss << "ParseEmberElement() : Color element with bad/missing index attribute " << index; - AddToReport(ss.str()); - } + while (index >= currentEmber.m_Palette.Size()) + currentEmber.m_Palette.m_Entries.push_back(v4F()); + + float alphaPercent = a / 255.0f;//Aplha percentage in the range of 0 to 1. + //Premultiply the palette. + currentEmber.m_Palette.m_Entries[index].r = alphaPercent * (r / 255.0f);//Palette colors are [0..255], convert to [0..1]. + currentEmber.m_Palette.m_Entries[index].g = alphaPercent * (g / 255.0f); + currentEmber.m_Palette.m_Entries[index].b = alphaPercent * (b / 255.0f); + currentEmber.m_Palette.m_Entries[index].a = a / 255.0f;//Will be one for RGB, and other than one if RGBA with A != 255. } else if (!Compare(childNode->name, "colors")) { @@ -2487,12 +2480,16 @@ bool XmlToEmber::ParseHexColors(const char* colstr, Ember& ember, size_t n for (size_t strIndex = 0; strIndex < length;) { - for (glm::length_t i = 0; i < 3 && colorCount < ember.m_Palette.Size(); i++) + for (glm::length_t i = 0; i < 3; i++) { const char tmpStr[3] = { s[strIndex++], s[strIndex++], 0 };//Read out and convert the string two characters at a time. ss.clear();//Reset and fill the string stream. ss.str(tmpStr); ss >> tmp;//Do the conversion. + + while (colorCount >= ember.m_Palette.Size()) + ember.m_Palette.m_Entries.push_back(v4F()); + ember.m_Palette.m_Entries[colorCount][i] = float(tmp) / 255.0f;//Hex palette is [0..255], convert to [0..1]. } diff --git a/Source/EmberCL/EmberCLStructs.h b/Source/EmberCL/EmberCLStructs.h index 5872c24..1549bf9 100644 --- a/Source/EmberCL/EmberCLStructs.h +++ b/Source/EmberCL/EmberCLStructs.h @@ -70,8 +70,6 @@ static string ConstantDefinesString(bool doublePrecision) "#define NTHREADS 256u\n" "#define THREADS_PER_WARP 32u\n" "#define NWARPS (NTHREADS / THREADS_PER_WARP)\n" - "#define COLORMAP_LENGTH 256u\n" - "#define COLORMAP_LENGTH_MINUS_1 255\n" "#define DE_THRESH 100u\n" "#define BadVal(x) (isnan(x))\n" "#define SQR(x) ((x) * (x))\n" @@ -206,6 +204,8 @@ struct ALIGN EmberCL m3T m_CamMat; T m_CenterX, m_CenterY; T m_RotA, m_RotB, m_RotD, m_RotE; + T m_Psm1; + T m_Psm2; }; /// @@ -232,6 +232,8 @@ static const char* EmberCLStructString = " real_t m_C22;\n" " real_t m_CenterX, m_CenterY;\n" " real_t m_RotA, m_RotB, m_RotD, m_RotE;\n" + " real_t m_Psm1;\n" + " real_t m_Psm2;\n" "} EmberCL;\n" "\n"; diff --git a/Source/EmberCL/FunctionMapper.cpp b/Source/EmberCL/FunctionMapper.cpp index 8653d3a..aea25a4 100644 --- a/Source/EmberCL/FunctionMapper.cpp +++ b/Source/EmberCL/FunctionMapper.cpp @@ -412,21 +412,21 @@ FunctionMapper::FunctionMapper() " return 0.0;\n" " }\n" "\n" - " if (w <= 4) // w in (0, 4]\n" + " if (w <= 4)\n" " {\n" " real_t y = x * x;\n" " r = EvalRational(P1, Q1, y, 7);\n" " factor = w * (w + x1) * ((w - x11 / 256) - x12);\n" " value = factor * r;\n" " }\n" - " else if (w <= 8) // w in (4, 8]\n" + " else if (w <= 8)\n" " {\n" " real_t y = x * x;\n" " r = EvalRational(P2, Q2, y, 8);\n" " factor = w * (w + x2) * ((w - x21 / 256) - x22);\n" " value = factor * r;\n" " }\n" - " else // w in (8, \infty)\n" + " else\n" " {\n" " real_t y = 8 / w;\n" " real_t y2 = y * y;\n" @@ -440,7 +440,7 @@ FunctionMapper::FunctionMapper() "\n" " if (x < 0)\n" " {\n" - " value *= -1; // odd function\n" + " value *= -1;\n" " }\n" "\n" " return value;\n" diff --git a/Source/EmberCL/IterOpenCLKernelCreator.cpp b/Source/EmberCL/IterOpenCLKernelCreator.cpp index d811e5b..ddaec0a 100644 --- a/Source/EmberCL/IterOpenCLKernelCreator.cpp +++ b/Source/EmberCL/IterOpenCLKernelCreator.cpp @@ -471,23 +471,24 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember, { os << " real_t colorIndexFrac;\n" - " real_t colorIndex = secondPoint.m_ColorX * COLORMAP_LENGTH_MINUS_1;\n" - " int intColorIndex = (int)colorIndex;\n" + " real_t colorIndex = secondPoint.m_ColorX * ember->m_Psm1;\n" + " int intColorIndex;\n" " float4 palColor2;\n" "\n" - " if (intColorIndex < 0)\n" + " if (colorIndex < 0)\n" " {\n" " intColorIndex = 0;\n" " colorIndexFrac = 0;\n" " }\n" - " else if (intColorIndex >= COLORMAP_LENGTH_MINUS_1)\n" + " else if (colorIndex >= ember->m_Psm1)\n" " {\n" - " intColorIndex = COLORMAP_LENGTH_MINUS_1 - 1;\n" + " intColorIndex = (int)ember->m_Psm2;\n" " colorIndexFrac = 1.0;\n" " }\n" " else\n" " {\n" - " colorIndexFrac = colorIndex - (real_t)intColorIndex;\n"//Interpolate between intColorIndex and intColorIndex + 1. + " intColorIndex = (int)colorIndex;\n" + " colorIndexFrac = colorIndex - intColorIndex;\n"//Interpolate between intColorIndex and intColorIndex + 1. " }\n" "\n" " iPaletteCoord.x = intColorIndex;\n"//Palette operations are strictly float because OpenCL does not support dp64 textures. @@ -499,7 +500,7 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember, else if (ember.m_PaletteMode == ePaletteMode::PALETTE_STEP) { os << - " iPaletteCoord.x = (int)(secondPoint.m_ColorX * COLORMAP_LENGTH_MINUS_1);\n" + " iPaletteCoord.x = (int)(secondPoint.m_ColorX * ember->m_Psm1);\n" " palColor1 = read_imagef(palette, paletteSampler, iPaletteCoord);\n"; } diff --git a/Source/EmberCL/OpenCLWrapper.cpp b/Source/EmberCL/OpenCLWrapper.cpp index cf26ec3..b319e29 100644 --- a/Source/EmberCL/OpenCLWrapper.cpp +++ b/Source/EmberCL/OpenCLWrapper.cpp @@ -393,12 +393,10 @@ bool OpenCLWrapper::AddAndWriteImage(const string& name, cl_mem_flags flags, con if (m_Info->CheckCL(err, "cl::ImageGL()")) { m_GLImages.push_back(namedImageGL); - - if (data) - return WriteImage2D(m_GLImages.size() - 1, true, width, height, row_pitch, data);//OpenGL images/textures require a separate write. - else - return true; + imageIndex = int(m_GLImages.size()) - 1; } + else + return false; } else { @@ -407,8 +405,10 @@ bool OpenCLWrapper::AddAndWriteImage(const string& name, cl_mem_flags flags, con if (m_Info->CheckCL(err, "cl::Image2D()")) { m_Images.push_back(namedImage); - return true; + imageIndex = int(m_Images.size()) - 1; } + else + return false; } } else//It did exist, so create new if sizes are different. Write if data is not NULL. @@ -422,18 +422,10 @@ bool OpenCLWrapper::AddAndWriteImage(const string& name, cl_mem_flags flags, con NamedImage2DGL namedImageGL(cl::ImageGL(m_Context, flags, GL_TEXTURE_2D, 0, texName, &err), name);//Sizes are different, so create new. if (m_Info->CheckCL(err, "cl::ImageGL()")) - { m_GLImages[imageIndex] = namedImageGL; - } else return false; } - - //Write data to new image since OpenGL images/textures require a separate write, must match new size. - if (data) - return WriteImage2D(imageIndex, true, width, height, row_pitch, data); - else - return true; } else { @@ -443,17 +435,17 @@ bool OpenCLWrapper::AddAndWriteImage(const string& name, cl_mem_flags flags, con NamedImage2D namedImage(cl::Image2D(m_Context, flags, format, width, height, row_pitch, data, &err), name); if (m_Info->CheckCL(err, "cl::Image2D()")) - { m_Images[imageIndex] = namedImage; - return true; - } + else + return false; } - else if (data) - return WriteImage2D(imageIndex, false, width, height, row_pitch, data); - else//Strange case: images were same dimensions but no data was passed in, so do nothing. - return true; } } + + if (data) + return WriteImage2D(imageIndex, shared, width, height, row_pitch, data); + else//Strange case: images were same dimensions but no data was passed in, so do nothing. + return true; } return false; diff --git a/Source/EmberCL/RendererCL.cpp b/Source/EmberCL/RendererCL.cpp index 0c34e62..1a5471a 100644 --- a/Source/EmberCL/RendererCL.cpp +++ b/Source/EmberCL/RendererCL.cpp @@ -81,7 +81,7 @@ bool RendererCL::Init(const vector>& devices, b { if (b && !(b = cld->m_Wrapper.AddProgram(m_IterOpenCLKernelCreator.ZeroizeEntryPoint(), zeroizeProgram, m_IterOpenCLKernelCreator.ZeroizeEntryPoint(), m_DoublePrecision))) { ErrorStr(loc, "Failed to init zeroize program: "s + cld->ErrorReportString(), cld.get()); } - if (b && !(b = cld->m_Wrapper.AddAndWriteImage("Palette", CL_MEM_READ_ONLY, m_PaletteFormat, 256, 1, 0, nullptr))) { ErrorStr(loc, "Failed to init palette buffer: "s + cld->ErrorReportString(), cld.get()); } + if (b && !(b = cld->m_Wrapper.AddAndWriteImage("Palette", CL_MEM_READ_ONLY, m_PaletteFormat, m_Ember.m_Palette.Size(), 1, 0, nullptr))) { ErrorStr(loc, "Failed to init palette buffer: "s + cld->ErrorReportString(), cld.get()); } if (b && !(b = cld->m_Wrapper.AddAndWriteBuffer(m_GlobalSharedBufferName, m_GlobalShared.second.data(), m_GlobalShared.second.size() * sizeof(m_GlobalShared.second[0])))) { ErrorStr(loc, "Failed to init global shared buffer: "s + cld->ErrorReportString(), cld.get()); }//Empty at start, will be filled in later if needed. @@ -853,7 +853,7 @@ EmberStats RendererCL::Iterate(size_t iterCount, size_t temporalSamp break; } - if (b && !(b = wrapper.AddAndWriteImage("Palette", CL_MEM_READ_ONLY, m_PaletteFormat, m_Dmap.m_Entries.size(), 1, 0, m_Dmap.m_Entries.data()))) + if (b && !(b = wrapper.AddAndWriteImage("Palette", CL_MEM_READ_ONLY, m_PaletteFormat, m_Dmap.Size(), 1, 0, m_Dmap.m_Entries.data()))) { ErrorStr(loc, "Write palette buffer failed", device.get()); break; @@ -1787,6 +1787,8 @@ void RendererCL::ConvertEmber(Ember& ember, EmberCL& emberCL, emberCL.m_RotB = m_RotMat.B(); emberCL.m_RotD = m_RotMat.D(); emberCL.m_RotE = m_RotMat.E(); + emberCL.m_Psm1 = T(m_Dmap.Size() - 1); + emberCL.m_Psm2 = T(m_Dmap.Size() - 2); for (size_t i = 0; i < ember.TotalXformCount() && i < xformsCL.size(); i++) { diff --git a/Source/Fractorium/FractoriumEmberController.h b/Source/Fractorium/FractoriumEmberController.h index 5a975a7..918b464 100644 --- a/Source/Fractorium/FractoriumEmberController.h +++ b/Source/Fractorium/FractoriumEmberController.h @@ -248,6 +248,7 @@ public: virtual void PaletteCellClicked(int row, int col) { } virtual void SetBasePaletteAndAdjust(const Palette& palette) { } virtual void PaletteEditorButtonClicked() { } + virtual void PaletteEditorColorChanged() { } QImage& FinalPaletteImage() { return m_FinalPaletteImage; } //Info. @@ -535,6 +536,7 @@ public: virtual void PaletteCellClicked(int row, int col) override; virtual void SetBasePaletteAndAdjust(const Palette& palette) override; virtual void PaletteEditorButtonClicked() override; + virtual void PaletteEditorColorChanged() override; //Info. virtual void FillSummary() override; diff --git a/Source/Fractorium/FractoriumPalette.cpp b/Source/Fractorium/FractoriumPalette.cpp index 66cc524..45467d7 100644 --- a/Source/Fractorium/FractoriumPalette.cpp +++ b/Source/Fractorium/FractoriumPalette.cpp @@ -406,7 +406,7 @@ void FractoriumEmberController::PaletteEditorButtonClicked() if (auto xform = m_Ember.GetTotalXform(index.first, forceFinal)) xform->m_ColorX = index.second; - edPal = ed->GetPalette(int(256)); + edPal = ed->GetPalette(int(prevPal.Size())); SetBasePaletteAndAdjust(edPal);//This will take care of updating the color index controls. if (edPal.m_Filename.get() && !edPal.m_Filename->empty()) @@ -458,10 +458,16 @@ void Fractorium::OnPaletteEditorButtonClicked(bool checked) /// /// Slot called every time a color is changed in the palette editor. /// +template +void FractoriumEmberController::PaletteEditorColorChanged() +{ + SetBasePaletteAndAdjust(m_Fractorium->m_PaletteEditor->GetPalette(int(m_TempPalette.Size()))); +} + void Fractorium::OnPaletteEditorColorChanged() { m_PaletteChanged = true; - m_Controller->SetBasePaletteAndAdjust(m_PaletteEditor->GetPalette(int(256))); + m_Controller->PaletteEditorColorChanged(); } /// @@ -569,7 +575,7 @@ void Fractorium::SetPaletteFileComboIndex(const string& filename) /// /// Reset the color curve values for the selected curve in the current ember to their default state and also update the curves control. /// Called when ResetCurvesButton is clicked. -/// Note if they click Reset Curves when the "All" radio button is selected, then it clears all curves. +/// Note if they click Reset Curves when the ctrl is pressed, then it clears all curves. /// Resets the rendering process at either ACCUM_ONLY by default, or FILTER_AND_ACCUM when using early clip. /// /// The index of the curve to be cleared, 0 to clear all. @@ -578,26 +584,34 @@ void FractoriumEmberController::ClearColorCurves(int i) { Update([&] { - if (i) - m_Ember.m_Curves.Init(i); - else - m_Ember.m_Curves.Init(0); + m_Ember.m_Curves.Init(i); + }, true, m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY); FillCurvesControl(); } void Fractorium::OnResetCurvesButtonClicked(bool checked) { - if (ui.CurvesAllRadio->isChecked()) - m_Controller->ClearColorCurves(0); - else if (ui.CurvesRedRadio->isChecked()) - m_Controller->ClearColorCurves(1); - else if (ui.CurvesGreenRadio->isChecked()) - m_Controller->ClearColorCurves(2); - else if (ui.CurvesBlueRadio->isChecked()) - m_Controller->ClearColorCurves(3); + if (!QGuiApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) + { + if (ui.CurvesAllRadio->isChecked()) + m_Controller->ClearColorCurves(0); + else if (ui.CurvesRedRadio->isChecked()) + m_Controller->ClearColorCurves(1); + else if (ui.CurvesGreenRadio->isChecked()) + m_Controller->ClearColorCurves(2); + else if (ui.CurvesBlueRadio->isChecked()) + m_Controller->ClearColorCurves(3); + else + m_Controller->ClearColorCurves(0); + } else + { m_Controller->ClearColorCurves(0); + m_Controller->ClearColorCurves(1); + m_Controller->ClearColorCurves(2); + m_Controller->ClearColorCurves(3); + } } /// diff --git a/Source/Fractorium/FractoriumParams.cpp b/Source/Fractorium/FractoriumParams.cpp index 1a83846..1b2d29c 100644 --- a/Source/Fractorium/FractoriumParams.cpp +++ b/Source/Fractorium/FractoriumParams.cpp @@ -22,12 +22,12 @@ void Fractorium::InitParamsUI() SetFixedTableHeader(ui.IterationTableHeader->horizontalHeader()); SetFixedTableHeader(ui.AnimationTableHeader->horizontalHeader()); //Color. - SetupSpinner(table, this, row, 1, m_BrightnessSpin, spinHeight, 0.05, 1000, 1, SIGNAL(valueChanged(double)), SLOT(OnBrightnessChanged(double)), true, 4.0, 4.0, 4.0); - SetupSpinner(table, this, row, 1, m_GammaSpin, spinHeight, 1, 9999, 0.5, SIGNAL(valueChanged(double)), SLOT(OnGammaChanged(double)), true, 4.0, 4.0, 4.0); - SetupSpinner(table, this, row, 1, m_GammaThresholdSpin, spinHeight, 0, 10, 0.01, SIGNAL(valueChanged(double)), SLOT(OnGammaThresholdChanged(double)), true, 0.1, 0.1, 0.0); - SetupSpinner(table, this, row, 1, m_VibrancySpin, spinHeight, 0, 30, 0.01, SIGNAL(valueChanged(double)), SLOT(OnVibrancyChanged(double)), true, 1.0, 1.0, 0.0); + SetupSpinner(table, this, row, 1, m_BrightnessSpin, spinHeight, 0.01, dmax, 1, SIGNAL(valueChanged(double)), SLOT(OnBrightnessChanged(double)), true, 4.0, 4.0, 4.0); + SetupSpinner(table, this, row, 1, m_GammaSpin, spinHeight, 1, dmax, 0.5, SIGNAL(valueChanged(double)), SLOT(OnGammaChanged(double)), true, 4.0, 4.0, 4.0); + SetupSpinner(table, this, row, 1, m_GammaThresholdSpin, spinHeight, 0, dmax, 0.01, SIGNAL(valueChanged(double)), SLOT(OnGammaThresholdChanged(double)), true, 0.1, 0.1, 0.0); + SetupSpinner(table, this, row, 1, m_VibrancySpin, spinHeight, 0, dmax, 0.01, SIGNAL(valueChanged(double)), SLOT(OnVibrancyChanged(double)), true, 1.0, 1.0, 0.0); SetupSpinner(table, this, row, 1, m_HighlightSpin, spinHeight, -1.0, 10, 0.1, SIGNAL(valueChanged(double)), SLOT(OnHighlightPowerChanged(double)), true, 1.0, 1.0, -1.0); - SetupSpinner(table, this, row, 1, m_K2Spin, spinHeight, 0, 10.0, 0.0001, SIGNAL(valueChanged(double)), SLOT(OnK2Changed(double)), true, 0, 0.0001, 0); + SetupSpinner(table, this, row, 1, m_K2Spin, spinHeight, 0, 99.0, 0.0001, SIGNAL(valueChanged(double)), SLOT(OnK2Changed(double)), true, 0, 0.0001, 0); m_HighlightSpin->DoubleClickLowVal(-1.0); int dec = 6; m_BrightnessSpin->setDecimals(dec); diff --git a/Source/Fractorium/FractoriumXformsColor.cpp b/Source/Fractorium/FractoriumXformsColor.cpp index 1713636..e2020f3 100644 --- a/Source/Fractorium/FractoriumXformsColor.cpp +++ b/Source/Fractorium/FractoriumXformsColor.cpp @@ -229,7 +229,7 @@ void Fractorium::OnXformRefPaletteResized(int logicalIndex, int oldSize, int new template QColor FractoriumEmberController::ColorIndexToQColor(double d) { - v4F entry = m_Ember.m_Palette[Clamp(d * COLORMAP_LENGTH_MINUS_1, 0, m_Ember.m_Palette.Size())]; + v4F entry = m_Ember.m_Palette[Clamp(d * (m_Ember.m_Palette.Size() - 1), 0, m_Ember.m_Palette.Size())]; entry.r *= 255; entry.g *= 255; entry.b *= 255;