diff --git a/Source/Ember/Affine2D.h b/Source/Ember/Affine2D.h index a96f6c6..4960e8c 100644 --- a/Source/Ember/Affine2D.h +++ b/Source/Ember/Affine2D.h @@ -87,6 +87,7 @@ public: m4T ToMat4ColMajor(bool center = false) const; m4T ToMat4RowMajor(bool center = false) const; + //Note that returning a copy is actually faster than a const ref&. T A() const; T B() const; T C() const; diff --git a/Source/Ember/Palette.h b/Source/Ember/Palette.h index ea3f78b..f339649 100644 --- a/Source/Ember/Palette.h +++ b/Source/Ember/Palette.h @@ -578,7 +578,7 @@ public: int m_Index;//Index in the xml palette file of this palette, use -1 for random. string m_Name;//Name of this palette. - string m_Filename;//Name of the parent file this palette came from, can be empty. + shared_ptr m_Filename;//Name of the parent file this palette came from, can be empty. vector m_Entries;//Storage for the color values. }; } diff --git a/Source/Ember/PaletteList.h b/Source/Ember/PaletteList.h index 1fbd65f..37070e5 100644 --- a/Source/Ember/PaletteList.h +++ b/Source/Ember/PaletteList.h @@ -51,11 +51,12 @@ public: if (doc != nullptr) { - xmlNode* rootNode = xmlDocGetRootElement(doc); + auto rootNode = xmlDocGetRootElement(doc); + auto pfilename = shared_ptr(new string(filename)); palettes.clear(); palettes.reserve(buf.size() / 2048);//Roughly what it takes per palette. - ParsePalettes(rootNode, filename, palettes); + ParsePalettes(rootNode, pfilename, palettes); xmlFreeDoc(doc); added = true; } @@ -226,7 +227,7 @@ private: /// The parent note of all palettes in the Xml file. /// The name of the Xml file. /// The vector to store the paresed palettes associated with this file in. - void ParsePalettes(xmlNode* node, const string& filename, vector>& palettes) + void ParsePalettes(xmlNode* node, const shared_ptr& filename, vector>& palettes) { bool hexError = false; char* val; diff --git a/Source/EmberCL/RendererCL.cpp b/Source/EmberCL/RendererCL.cpp index 4aa0e2a..ca663d3 100644 --- a/Source/EmberCL/RendererCL.cpp +++ b/Source/EmberCL/RendererCL.cpp @@ -1475,18 +1475,23 @@ CarToRasCL RendererCL::ConvertCarToRas(const CarToRas& carToRas) /// /// Fill seeds buffer which gets passed to the iteration kernel. +/// The range of each seed will be spaced to ensure no duplicates are added. /// Note, WriteBuffer() must be called after this to actually copy the /// data from the host to the device. /// template void RendererCL::FillSeeds() { + double start, delta = std::floor((double)std::numeric_limits::max() / (IterGridKernelCount() * 2)); m_Seeds.resize(IterGridKernelCount()); + start = delta; for (auto& seed : m_Seeds) { - seed.x = m_Rand[0].Rand(); - seed.y = m_Rand[0].Rand(); + seed.x = (uint)m_Rand[0].Frand(start, start + delta); + start += delta; + seed.y = (uint)m_Rand[0].Frand(start, start + delta); + start += delta; } } diff --git a/Source/Fractorium/Fractorium.h b/Source/Fractorium/Fractorium.h index 8d99d89..f4d8d51 100644 --- a/Source/Fractorium/Fractorium.h +++ b/Source/Fractorium/Fractorium.h @@ -121,6 +121,8 @@ public slots: void OnActionCopyAllXml(bool checked); void OnActionPasteXmlAppend(bool checked); void OnActionPasteXmlOver(bool checked); + void OnActionCopySelectedXforms(bool checked); + void OnActionPasteSelectedXforms(bool checked); void OnActionAddReflectiveSymmetry(bool checked);//Tools. void OnActionAddRotationalSymmetry(bool checked); diff --git a/Source/Fractorium/Fractorium.ui b/Source/Fractorium/Fractorium.ui index c7f0580..12e5630 100644 --- a/Source/Fractorium/Fractorium.ui +++ b/Source/Fractorium/Fractorium.ui @@ -170,6 +170,9 @@ + + + @@ -6104,7 +6107,7 @@ SpinBox :/Fractorium/Icons/page_paste.png:/Fractorium/Icons/page_paste.png - Paste Xml &Append + Paste Xml A&ppend Ctrl+V @@ -6139,6 +6142,28 @@ SpinBox Fl&ip + + + Copy Selected &Xforms + + + Copy selected xforms to the clipboard + + + Ctrl+Q + + + + + Paste Selected X&forms + + + Paste copied xforms into the current flame + + + Ctrl+W + + diff --git a/Source/Fractorium/FractoriumEmberController.h b/Source/Fractorium/FractoriumEmberController.h index 32653b6..5ac75de 100644 --- a/Source/Fractorium/FractoriumEmberController.h +++ b/Source/Fractorium/FractoriumEmberController.h @@ -94,6 +94,8 @@ public: virtual void CopyAllXml() { } virtual void PasteXmlAppend() { } virtual void PasteXmlOver() { } + virtual void CopySelectedXforms() { } + virtual void PasteSelectedXforms() { } virtual void AddReflectiveSymmetry() { }//Tools. virtual void AddRotationalSymmetry() { } virtual void AddBothSymmetry() { } @@ -323,6 +325,8 @@ public: virtual void CopyAllXml() override; virtual void PasteXmlAppend() override; virtual void PasteXmlOver() override; + virtual void CopySelectedXforms() override; + virtual void PasteSelectedXforms() override; virtual void AddReflectiveSymmetry() override; virtual void AddRotationalSymmetry() override; virtual void AddBothSymmetry() override; @@ -477,6 +481,8 @@ private: Ember m_Ember; EmberFile m_EmberFile; deque> m_UndoList; + vector> m_CopiedXforms; + Xform m_CopiedFinalXform; Palette m_TempPalette; PaletteList m_PaletteList; VariationList m_VariationList; diff --git a/Source/Fractorium/FractoriumMenus.cpp b/Source/Fractorium/FractoriumMenus.cpp index bb86d20..0e80710 100644 --- a/Source/Fractorium/FractoriumMenus.cpp +++ b/Source/Fractorium/FractoriumMenus.cpp @@ -25,6 +25,9 @@ void Fractorium::InitMenusUI() connect(ui.ActionCopyAllXml, SIGNAL(triggered(bool)), this, SLOT(OnActionCopyAllXml(bool)), Qt::QueuedConnection); connect(ui.ActionPasteXmlAppend, SIGNAL(triggered(bool)), this, SLOT(OnActionPasteXmlAppend(bool)), Qt::QueuedConnection); connect(ui.ActionPasteXmlOver, SIGNAL(triggered(bool)), this, SLOT(OnActionPasteXmlOver(bool)), Qt::QueuedConnection); + connect(ui.ActionCopySelectedXforms, SIGNAL(triggered(bool)), this, SLOT(OnActionCopySelectedXforms(bool)), Qt::QueuedConnection); + connect(ui.ActionPasteSelectedXforms, SIGNAL(triggered(bool)), this, SLOT(OnActionPasteSelectedXforms(bool)), Qt::QueuedConnection); + ui.ActionPasteSelectedXforms->setEnabled(false); //Tools menu. connect(ui.ActionAddReflectiveSymmetry, SIGNAL(triggered(bool)), this, SLOT(OnActionAddReflectiveSymmetry(bool)), Qt::QueuedConnection); @@ -609,6 +612,57 @@ void FractoriumEmberController::PasteXmlOver() void Fractorium::OnActionPasteXmlOver(bool checked) { m_Controller->PasteXmlOver(); } +/// +/// Copy the selected xforms. +/// Note this will also copy final if selected. +/// If none selected, just copy current. +/// +template +void FractoriumEmberController::CopySelectedXforms() +{ + m_CopiedXforms.clear(); + m_CopiedFinalXform.Clear(); + + UpdateXform([&](Xform* xform) + { + if (m_Ember.IsFinalXform(xform)) + m_CopiedFinalXform = *xform; + else + m_CopiedXforms.push_back(*xform); + }, UPDATE_SELECTED, false); + m_Fractorium->ui.ActionPasteSelectedXforms->setEnabled(true); +} + +void Fractorium::OnActionCopySelectedXforms(bool checked) +{ + m_Controller->CopySelectedXforms(); +} + +/// +/// Paste the selected xforms. +/// Note this will also paste/overwrite final if previously copied. +/// Resets the rendering process. +/// +template +void FractoriumEmberController::PasteSelectedXforms() +{ + Update([&]() + { + for (auto& it : m_CopiedXforms) + m_Ember.AddXform(it); + + if (!m_CopiedFinalXform.Empty()) + m_Ember.SetFinalXform(m_CopiedFinalXform); + + FillXforms(); + }); +} + +void Fractorium::OnActionPasteSelectedXforms(bool checked) +{ + m_Controller->PasteSelectedXforms(); +} + /// /// Add reflective symmetry to the current ember. /// Resets the rendering process. diff --git a/Source/Fractorium/FractoriumParams.cpp b/Source/Fractorium/FractoriumParams.cpp index 9dca265..f434f14 100644 --- a/Source/Fractorium/FractoriumParams.cpp +++ b/Source/Fractorium/FractoriumParams.cpp @@ -562,7 +562,11 @@ void FractoriumEmberController::FillParamTablesAndPalette() //Use the ember's embedded palette, rather than one from the list, so assign it directly to the controls without applying adjustments. //Normally, the temp palette is assigned whenever the user clicks on a palette cell. But since that is skipped here, must do it manually. m_TempPalette = m_Ember.m_Palette; - m_Fractorium->SetPaletteFileComboIndex(m_Ember.m_Palette.m_Filename); + auto temp = m_Ember.m_Palette.m_Filename; + + if (temp.get()) + m_Fractorium->SetPaletteFileComboIndex(*temp.get()); + UpdateAdjustedPaletteGUI(m_Ember.m_Palette);//Setting the palette will trigger a full render. }