--User changes

-Remove the option --intpalette to format the palette in the xml as ints. If they are not hex formatted, then they should always be float. This option was pointless.
 -Cleanup some options text for the command line programs.
 -Allow for dragging around flames in the library tab. This is useful for setting up the order of an animation.
 -Make the opening of large files in Fractorium much more efficient when not-appending.
 -Make the opening of large files in all EmberRender and EmberAnimate more efficient.
 -Better error reporting when opening files.

--Bug fixes
 -Get rid of leftover artifacts that would appear on preview thumbnails when either switching SP/DP or re-rendering previews.
 -Filename extension was not being appended on Linux when saving as Xml, thus making it impossible to drag that file back in becase drop is filtered on extension.

--Code changes
 -Move GCC compiler spec to C++14. Building with 5.3 now on linux.
 -Use inline member data initializers.
 -Make a #define for static for use in Utils.h to make things a little cleaner.
 -Make various functions able to take arbitrary collections as their parameters rather than just vectors.
 -Make library collection a list rather than vector. This alleviates the need to re-sync pointers whenever the collection changes.
 -Subclass QTreeWidget for the library tree. Two new files added for this.
 -Remove all usage of #ifdef ROW_ONLY_DE in DEOpenCLKernelCreator, it was never used.
 -Add move constructor and assignment operator to EmberFile.
 -Add the ability to use a pointer to outside memory in the renderer for the vector of Ember<T>.
 -Make a lot more functions const where they should be.
This commit is contained in:
mfeemster
2016-04-03 18:55:12 -07:00
parent 124f807772
commit b690bf8071
64 changed files with 890 additions and 1048 deletions

View File

@ -15,7 +15,7 @@ class FractoriumAboutDialog : public QDialog
{
Q_OBJECT
public:
FractoriumAboutDialog(QWidget* p = 0, Qt::WindowFlags f = 0);
FractoriumAboutDialog(QWidget* p = nullptr, Qt::WindowFlags f = 0);
private:
Ui::AboutDialog ui;

View File

@ -16,7 +16,7 @@ class DoubleSpinBox : public QDoubleSpinBox
Q_OBJECT
public:
explicit DoubleSpinBox(QWidget* parent = 0, int height = 16, double step = 0.05);
explicit DoubleSpinBox(QWidget* parent = nullptr, int height = 16, double step = 0.05);
virtual ~DoubleSpinBox() { }
void SetValueStealth(double d);
void DoubleClick(bool b);

View File

@ -17,11 +17,10 @@ class EmberFile
{
public:
/// <summary>
/// Empty constructor that does nothing.
/// Default constructor and destructor.
/// </summary>
EmberFile()
{
}
EmberFile() = default;
~EmberFile() = default;
/// <summary>
/// Default copy constructor.
@ -63,7 +62,31 @@ public:
EmberFile<T>& operator = (const EmberFile<U>& emberFile)
{
m_Filename = emberFile.m_Filename;
CopyVec(m_Embers, emberFile.m_Embers);
CopyCont(m_Embers, emberFile.m_Embers);
return *this;
}
/// <summary>
/// Move constructor.
/// </summary>
/// <param name="emberFile">The EmberFile object to move</param>
EmberFile(EmberFile<T>&& emberFile)
{
EmberFile<T>::operator=<T>(emberFile);
}
/// <summary>
/// Move assignment operator.
/// </summary>
/// <param name="emberFile">The EmberFile object to move</param>
EmberFile<T>& operator = (EmberFile<T>&& emberFile)
{
if (this != &emberFile)
{
m_Filename = emberFile.m_Filename;
m_Embers = std::move(emberFile.m_Embers);
}
return *this;
}
@ -84,6 +107,19 @@ public:
return m_Embers.size();
}
/// <summary>
/// Get a pointer to the ember at the specified index.
/// </summary>
/// <param name="i">The index of the ember to retrieve</param>
/// <returns>A pointer to the ember if it was within bounds, else nullptr.</returns>
Ember<T>* Get(size_t i)
{
if (i < m_Embers.size())
return &(*Advance(m_Embers.begin(), i));
return nullptr;
}
/// <summary>
/// Delete the ember at the given index.
/// Will not delete anything if the size is already 1.
@ -94,7 +130,7 @@ public:
{
if (Size() > 1 && index < Size())
{
m_Embers.erase(m_Embers.begin() + index);
m_Embers.erase(Advance(m_Embers.begin(), index));
return true;
}
else
@ -106,14 +142,14 @@ public:
/// </summary>
void MakeNamesUnique()
{
for (size_t i = 0; i < m_Embers.size(); i++)
for (auto it1 = m_Embers.begin(); it1 != m_Embers.end(); ++it1)
{
for (size_t j = 0; j < m_Embers.size(); j++)
for (auto it2 = m_Embers.begin(); it2 != m_Embers.end(); ++it2)
{
if (i != j && m_Embers[i].m_Name == m_Embers[j].m_Name)
if (it1 != it2 && it1->m_Name == it2->m_Name)
{
m_Embers[j].m_Name = IncrementTrailingUnderscoreInt(QString::fromStdString(m_Embers[j].m_Name)).toStdString();
j = 0;
it2->m_Name = IncrementTrailingUnderscoreInt(QString::fromStdString(it2->m_Name)).toStdString();
it2 = m_Embers.begin();
}
}
}
@ -195,5 +231,5 @@ public:
}
QString m_Filename;
vector<Ember<T>> m_Embers;
list<Ember<T>> m_Embers;
};

View File

@ -44,7 +44,7 @@ public:
{
int size = 64;
m_Image = QImage(width, height, QImage::Format_RGBA8888);
memcpy(m_Image.scanLine(0), v.data(), v.size() * sizeof(v[0]));//Memcpy the data in.
memcpy(m_Image.scanLine(0), v.data(), SizeOf(v));//Memcpy the data in.
m_Pixmap = QPixmap::fromImage(m_Image).scaled(QSize(size, size), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);//Create a QPixmap out of the QImage, scaled to size.
setData(0, Qt::DecorationRole, m_Pixmap);
}
@ -68,10 +68,11 @@ public:
/// </summary>
/// <param name="ember">A pointer to the ember this item will represent</param>
/// <param name="p">The parent widget of this item</param>
explicit EmberTreeWidgetItem(Ember<T>* ember, QTreeWidget* p = 0)
: EmberTreeWidgetItemBase(p)
explicit EmberTreeWidgetItem(Ember<T>* ember, QTreeWidget* p = nullptr)
: EmberTreeWidgetItemBase(p),
m_Ember(ember)
{
m_Ember = ember;
setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled);
}
/// <summary>
@ -80,10 +81,11 @@ public:
/// </summary>
/// <param name="ember">A pointer to the ember this item will represent</param>
/// <param name="p">The parent widget of this item</param>
explicit EmberTreeWidgetItem(Ember<T>* ember, QTreeWidgetItem* p = 0)
: EmberTreeWidgetItemBase(p)
explicit EmberTreeWidgetItem(Ember<T>* ember, QTreeWidgetItem* p = nullptr)
: EmberTreeWidgetItemBase(p),
m_Ember(ember)
{
m_Ember = ember;
setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled);
}
/// <summary>

View File

@ -10,13 +10,10 @@
/// </summary>
/// <param name="finalRender">Pointer to the final render dialog</param>
FinalRenderEmberControllerBase::FinalRenderEmberControllerBase(FractoriumFinalRenderDialog* finalRenderDialog)
: FractoriumEmberControllerBase(finalRenderDialog->m_Fractorium)
: FractoriumEmberControllerBase(finalRenderDialog->m_Fractorium),
m_FinalRenderDialog(finalRenderDialog)
{
m_Run = false;
m_PreviewRun = false;
m_ImageCount = 0;
m_FinishedImageCount.store(0);
m_FinalRenderDialog = finalRenderDialog;
m_Settings = m_Fractorium->m_Settings;
}
@ -105,7 +102,7 @@ template<typename T>
FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderDialog* finalRender)
: FinalRenderEmberControllerBase(finalRender)
{
m_FinalPreviewRenderer = unique_ptr<EmberNs::Renderer<T, float>>(new EmberNs::Renderer<T, float>());
m_FinalPreviewRenderer = make_unique<EmberNs::Renderer<T, float>>();
m_FinalPreviewRenderer->Callback(nullptr);
m_FinalPreviewRenderer->NumChannels(4);
m_FinalPreviewRenderFunc = [&]()
@ -157,10 +154,10 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
m_Run = true;
m_TotalTimer.Tic();//Begin timing for progress of all operations.
m_GuiState = m_FinalRenderDialog->State();//Cache render settings from the GUI before running.
size_t i;
size_t i = 0;
bool doAll = m_GuiState.m_DoAll && m_EmberFile.Size() > 1;
size_t currentStripForProgress = 0;//Sort of a hack to get the strip value to the progress function.
QString path = doAll ? ComposePath(QString::fromStdString(m_EmberFile.m_Embers[0].m_Name)) : ComposePath(Name());
QString path = doAll ? ComposePath(QString::fromStdString(m_EmberFile.m_Embers.begin()->m_Name)) : ComposePath(Name());
QString backup = path + "_backup.flame";
//Save backup Xml.
@ -186,33 +183,40 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
//Different action required for rendering as animation or not.
if (m_GuiState.m_DoSequence && !m_Renderers.empty())
{
Ember<T>* firstEmber = &m_EmberFile.m_Embers[0];
Ember<T>* prev = nullptr;
vector<Ember<T>> embers;
vector<std::thread> threadVec;
std::atomic<size_t> atomfTime;
auto firstEmber = m_EmberFile.m_Embers.begin();
//Need to loop through and set all w, h, q, ts, ss and t vals.
for (i = 0; i < m_EmberFile.Size() && m_Run; i++)
for (auto& it : m_EmberFile.m_Embers)
{
SyncGuiToEmber(m_EmberFile.m_Embers[i], firstEmber->m_FinalRasW, firstEmber->m_FinalRasH);
if (!m_Run)
break;
if (i > 0)
SyncGuiToEmber(it, firstEmber->m_FinalRasW, firstEmber->m_FinalRasH);
if (&it == &(*firstEmber))//First.
{
if (m_EmberFile.m_Embers[i].m_Time <= m_EmberFile.m_Embers[i - 1].m_Time)
m_EmberFile.m_Embers[i].m_Time = m_EmberFile.m_Embers[i - 1].m_Time + 1;
it.m_Time = 0;
}
else if (i == 0)
else//All others
{
m_EmberFile.m_Embers[i].m_Time = 0;
if (it.m_Time <= prev->m_Time)
it.m_Time = prev->m_Time + 1;
}
m_EmberFile.m_Embers[i].m_TemporalSamples = m_GuiState.m_TemporalSamples;
it.m_TemporalSamples = m_GuiState.m_TemporalSamples;
prev = &it;
}
std::atomic<size_t> atomfTime;
vector<std::thread> threadVec;
//Not supporting strips with animation.
//Shouldn't be a problem because animations will be at max 4k x 2k which will take about 1GB
//even when using double precision, which most cards at the time of this writing already exceed.
m_GuiState.m_Strips = 1;
atomfTime.store(0);
CopyCont(embers, m_EmberFile.m_Embers);
std::function<void(size_t)> iterFunc = [&](size_t index)
{
size_t ftime;
@ -223,13 +227,13 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
EmberImageComments comments;
Timing renderTimer;
auto renderer = m_Renderers[index].get();
renderer->SetEmber(m_EmberFile.m_Embers);//Copy all embers to the local storage inside the renderer.
renderer->SetExternalEmbersPointer(&embers);//All will share a pointer to the original vector to conserve memory with large files. Ok because the vec doesn't get modified.
//Render each image, cancelling if m_Run ever gets set to false.
while (atomfTime.fetch_add(1), ((ftime = atomfTime.load() - 1) < m_EmberFile.Size()) && m_Run)//Needed to set 1 to claim this iter from other threads, so decrement it to be zero-indexed here.
{
T localTime = T(ftime);
Output("Image " + ToString(ftime + 1ULL) + ":\n" + ComposePath(QString::fromStdString(m_EmberFile.m_Embers[ftime].m_Name)));
Output("Image " + ToString(ftime + 1ULL) + ":\n" + ComposePath(QString::fromStdString(m_EmberFile.Get(ftime)->m_Name)));
renderer->Reset();//Have to manually set this since the ember is not set each time through.
renderTimer.Tic();//Toc() is called in RenderComplete().
@ -247,10 +251,10 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
writeThread.join();
stats = renderer->Stats();
comments = renderer->ImageComments(stats, 0, false, true);
comments = renderer->ImageComments(stats, 0, true);
writeThread = std::thread([&](size_t tempTime, size_t threadFinalImageIndex)
{
SaveCurrentRender(m_EmberFile.m_Embers[tempTime],
SaveCurrentRender(*m_EmberFile.Get(tempTime),
comments,//These all don't change during the renders, so it's ok to access them in the thread.
finalImages[threadFinalImageIndex],
renderer->FinalRasW(),
@ -259,7 +263,7 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
renderer->BytesPerChannel());
}, ftime, finalImageIndex);
m_FinishedImageCount.fetch_add(1);
RenderComplete(m_EmberFile.m_Embers[ftime], stats, renderTimer);
RenderComplete(*m_EmberFile.Get(ftime), stats, renderTimer);
if (!index)//Only first device has a progress callback, so it also makes sense to only manually set the progress on the first device as well.
HandleFinishedProgress();
@ -290,16 +294,19 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
else if (m_Renderer.get())//Make sure a renderer was created and render all images, but not as an animation sequence (without temporal samples motion blur).
{
//Render each image, cancelling if m_Run ever gets set to false.
for (i = 0; i < m_EmberFile.Size() && m_Run; i++)
for (auto& it : m_EmberFile.m_Embers)
{
Output("Image " + ToString<qulonglong>(m_FinishedImageCount.load() + 1) + ":\n" + ComposePath(QString::fromStdString(m_EmberFile.m_Embers[i].m_Name)));
m_EmberFile.m_Embers[i].m_TemporalSamples = 1;//No temporal sampling.
m_Renderer->SetEmber(m_EmberFile.m_Embers[i]);
if (!m_Run)
break;
Output("Image " + ToString<qulonglong>(m_FinishedImageCount.load() + 1) + ":\n" + ComposePath(QString::fromStdString(it.m_Name)));
it.m_TemporalSamples = 1;//No temporal sampling.
m_Renderer->SetEmber(it);
m_Renderer->PrepFinalAccumVector(m_FinalImage);//Must manually call this first because it could be erroneously made smaller due to strips if called inside Renderer::Run().
m_Stats.Clear();
Memset(m_FinalImage);
m_RenderTimer.Tic();//Toc() is called in RenderComplete().
StripsRender<T>(m_Renderer.get(), m_EmberFile.m_Embers[i], m_FinalImage, 0, m_GuiState.m_Strips, m_GuiState.m_YAxisUp,
StripsRender<T>(m_Renderer.get(), it, m_FinalImage, 0, m_GuiState.m_Strips, m_GuiState.m_YAxisUp,
[&](size_t strip) { currentStripForProgress = strip; },//Pre strip.
[&](size_t strip) { m_Stats += m_Renderer->Stats(); },//Post strip.
[&](size_t strip)//Error.
@ -371,28 +378,24 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
template <typename T> void FinalRenderEmberController<T>::SetEmberFile(const EmberFile<float>& emberFile)
{
m_EmberFile = emberFile;
if (m_EmberFile.Size())
m_Ember = &(m_EmberFile.m_Embers[0]);
m_Ember = m_EmberFile.Get(0);
}
template <typename T> void FinalRenderEmberController<T>::CopyEmberFile(EmberFile<float>& emberFile, std::function<void(Ember<float>& ember)> perEmberOperation)
{
emberFile.m_Filename = m_EmberFile.m_Filename;
CopyVec(emberFile.m_Embers, m_EmberFile.m_Embers, perEmberOperation);
CopyCont(emberFile.m_Embers, m_EmberFile.m_Embers, perEmberOperation);
}
#ifdef DO_DOUBLE
template <typename T> void FinalRenderEmberController<T>::SetEmberFile(const EmberFile<double>& emberFile)
{
m_EmberFile = emberFile;
if (m_EmberFile.Size())
m_Ember = &(m_EmberFile.m_Embers[0]);
m_Ember = m_EmberFile.Get(0);
}
template <typename T> void FinalRenderEmberController<T>::CopyEmberFile(EmberFile<double>& emberFile, std::function<void(Ember<double>& ember)> perEmberOperation)
{
emberFile.m_Filename = m_EmberFile.m_Filename;
CopyVec(emberFile.m_Embers, m_EmberFile.m_Embers, perEmberOperation);
CopyCont(emberFile.m_Embers, m_EmberFile.m_Embers, perEmberOperation);
}
#endif
@ -407,12 +410,12 @@ void FinalRenderEmberController<T>::SetEmber(size_t index)
{
if (index < m_EmberFile.Size())
{
m_Ember = &(m_EmberFile.m_Embers[index]);
m_Ember = m_EmberFile.Get(index);
SyncCurrentToGui();
}
else if (m_EmberFile.Size() > 1)
{
m_Ember = &(m_EmberFile.m_Embers[0]);//Should never happen.
m_Ember = m_EmberFile.Get(0);//Should never happen.
}
}
@ -774,7 +777,7 @@ void FinalRenderEmberController<T>::CancelPreviewRender()
template<typename T>
void FinalRenderEmberController<T>::SaveCurrentRender(Ember<T>& ember)
{
auto comments = m_Renderer->ImageComments(m_Stats, 0, false, true);
auto comments = m_Renderer->ImageComments(m_Stats, 0, true);
SaveCurrentRender(ember, comments, m_FinalImage, m_Renderer->FinalRasW(), m_Renderer->FinalRasH(), m_Renderer->NumChannels(), m_Renderer->BytesPerChannel());
}

View File

@ -73,9 +73,9 @@ public:
void Output(const QString& s);
protected:
bool m_Run;
bool m_PreviewRun;
size_t m_ImageCount;
bool m_Run = false;
bool m_PreviewRun = false;
size_t m_ImageCount = 0;
std::atomic<size_t> m_FinishedImageCount;
QFuture<void> m_Result;

View File

@ -140,7 +140,7 @@ Fractorium::Fractorium(QWidget* p)
connect(ui.LibraryDockWidget, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(dockLocationChanged(Qt::DockWidgetArea)));
connect(ui.LibraryDockWidget, SIGNAL(topLevelChanged(bool)), this, SLOT(OnDockTopLevelChanged(bool)));
//Always ensure the library tab is selected, which will show preview renders.
//Always ensure the library tab is selected if not restoring, which will show preview renders.
if (!restored)
{
ui.LibraryDockWidget->raise();
@ -298,6 +298,7 @@ void Fractorium::dockLocationChanged(Qt::DockWidgetArea area)
/// Event filter for taking special action on:
/// Dock widget resize events, which in turn trigger GLParentScrollArea events.
/// Library tree key events, specifically delete.
/// Library tree drag n drop events.
/// </summary>
/// <param name="o">The object</param>
/// <param name="e">The eevent</param>
@ -309,7 +310,7 @@ bool Fractorium::eventFilter(QObject* o, QEvent* e)
m_WidthSpin->DoubleClickNonZero(ui.GLParentScrollArea->width());
m_HeightSpin->DoubleClickNonZero(ui.GLParentScrollArea->height());
}
else if (QKeyEvent* ke = dynamic_cast<QKeyEvent*>(e))
else if (auto ke = dynamic_cast<QKeyEvent*>(e))
{
bool shift = QGuiApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
@ -499,7 +500,7 @@ QStringList Fractorium::SetupOpenXmlDialog()
QStringList filenames;
m_FileDialog->disconnect(SIGNAL(filterSelected(const QString&)));
connect(m_FileDialog, &QFileDialog::filterSelected, [ = ](const QString & filter) { m_Settings->OpenXmlExt(filter); });
connect(m_FileDialog, &QFileDialog::filterSelected, [&](const QString & filter) { m_Settings->OpenXmlExt(filter); });
m_FileDialog->setFileMode(QFileDialog::ExistingFiles);
m_FileDialog->setAcceptMode(QFileDialog::AcceptOpen);
m_FileDialog->setNameFilter("Flam3 (*.flam3);;Flame (*.flame);;Xml (*.xml)");
@ -527,6 +528,7 @@ QStringList Fractorium::SetupOpenXmlDialog()
QString Fractorium::SetupSaveXmlDialog(const QString& defaultFilename)
{
//Lazy instantiate since it takes a long time.
//QS
if (!m_FileDialog)
{
m_FileDialog = new QFileDialog(this);
@ -538,7 +540,7 @@ QString Fractorium::SetupSaveXmlDialog(const QString& defaultFilename)
QString filename;
m_FileDialog->disconnect(SIGNAL(filterSelected(const QString&)));
connect(m_FileDialog, &QFileDialog::filterSelected, [ = ](const QString & filter) { m_Settings->SaveXmlExt(filter); });
connect(m_FileDialog, &QFileDialog::filterSelected, [&](const QString & filter) { m_Settings->SaveXmlExt(filter); });
//This must come first because it clears various internal states which allow the file text to be properly set.
//This is most likely a bug in QFileDialog.
m_FileDialog->setAcceptMode(QFileDialog::AcceptSave);
@ -549,7 +551,19 @@ QString Fractorium::SetupSaveXmlDialog(const QString& defaultFilename)
m_FileDialog->selectNameFilter(m_Settings->SaveXmlExt());
if (m_FileDialog->exec() == QDialog::Accepted)
{
filename = m_FileDialog->selectedFiles().value(0);
//For some reason, linux doesn't automatically append this, but Windows does. Force it to be safe.
auto filt = m_FileDialog->selectedNameFilter().split('*');//Qt makes it very hard to get the actual extension used.
if (filt.size() > 1)//Should always be true.
{
auto s = filt[1].replace(")", "");
if (!filename.endsWith(s))
filename.append(s);
}
}
return filename;
}
@ -574,7 +588,7 @@ QString Fractorium::SetupSaveImageDialog(const QString& defaultFilename)
QString filename;
m_FileDialog->disconnect(SIGNAL(filterSelected(const QString&)));
connect(m_FileDialog, &QFileDialog::filterSelected, [ = ](const QString & filter) { m_Settings->SaveImageExt(filter); });
connect(m_FileDialog, &QFileDialog::filterSelected, [&](const QString & filter) { m_Settings->SaveImageExt(filter); });
//This must come first because it clears various internal states which allow the file text to be properly set.
//This is most likely a bug in QFileDialog.
m_FileDialog->setAcceptMode(QFileDialog::AcceptSave);

View File

@ -65,6 +65,7 @@ class Fractorium : public QMainWindow
friend GLWidget;
friend QssDialog;
friend LibraryTreeWidget;
friend FractoriumOptionsDialog;
friend FractoriumFinalRenderDialog;
friend FractoriumAboutDialog;
@ -82,7 +83,7 @@ class Fractorium : public QMainWindow
#endif
public:
Fractorium(QWidget* p = 0);
Fractorium(QWidget* p = nullptr);
~Fractorium();
//Geometry.

View File

@ -6681,12 +6681,15 @@
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QTreeWidget" name="LibraryTree">
<widget class="LibraryTreeWidget" name="LibraryTree">
<property name="focusPolicy">
<enum>Qt::WheelFocus</enum>
</property>
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
<enum>Qt::DefaultContextMenu</enum>
</property>
<property name="acceptDrops">
<bool>false</bool>
</property>
<property name="frameShape">
<enum>QFrame::Panel</enum>
@ -6697,6 +6700,21 @@
<property name="editTriggers">
<set>QAbstractItemView::SelectedClicked</set>
</property>
<property name="showDropIndicator" stdset="0">
<bool>true</bool>
</property>
<property name="dragEnabled">
<bool>false</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::InternalMove</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::MoveAction</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="indentation">
<number>10</number>
</property>
@ -7239,6 +7257,11 @@
<extends>QGraphicsView</extends>
<header>CurvesGraphicsView.h</header>
</customwidget>
<customwidget>
<class>LibraryTreeWidget</class>
<extends>QTreeWidget</extends>
<header>LibraryTreeWidget.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>LibraryDockWidget</tabstop>

View File

@ -11,21 +11,12 @@
FractoriumEmberControllerBase::FractoriumEmberControllerBase(Fractorium* fractorium)
{
Timing t;
m_Rendering = false;
m_Shared = true;
m_FailedRenders = 0;
m_UndoIndex = 0;
m_LockedScale = 1;
m_RenderType = eRendererType::CPU_RENDERER;
m_OutputTexID = 0;
m_SubBatchCount = 1;//Will be ovewritten by the options on first render.
m_Fractorium = fractorium;
m_Info = OpenCLInfo::Instance();
m_Rand = QTIsaac<ISAAC_SIZE, ISAAC_INT>(ISAAC_INT(t.Tic()), ISAAC_INT(t.Tic() * 2), ISAAC_INT(t.Tic() * 3));//Ensure a different rand seed on each instance.
m_RenderTimer = std::unique_ptr<QTimer>(new QTimer(m_Fractorium));
m_RenderTimer = make_unique<QTimer>(m_Fractorium);
m_RenderTimer->setInterval(0);
m_Fractorium->connect(m_RenderTimer.get(), SIGNAL(timeout()), SLOT(IdleTimer()));
m_RenderRestartTimer = std::unique_ptr<QTimer>(new QTimer(m_Fractorium));
m_RenderRestartTimer = make_unique<QTimer>(m_Fractorium);
m_Fractorium->connect(m_RenderRestartTimer.get(), SIGNAL(timeout()), SLOT(StartRenderTimer()));
}
@ -52,10 +43,7 @@ FractoriumEmberController<T>::FractoriumEmberController(Fractorium* fractorium)
m_VariationList(VariationList<T>::Instance())
{
bool b = false;
m_PreviewRun = false;
m_PreviewRunning = false;
m_GLController = unique_ptr<GLEmberController<T>>(new GLEmberController<T>(fractorium, fractorium->ui.GLDisplay, this));
m_PreviewRenderer = unique_ptr<EmberNs::Renderer<T, float>>(new EmberNs::Renderer<T, float>());
m_GLController = make_unique<GLEmberController<T>>(fractorium, fractorium->ui.GLDisplay, this);
//Initial combo change event to fill the palette table will be called automatically later.
//Look hard for a palette.
static vector<string> paths =
@ -72,8 +60,7 @@ FractoriumEmberController<T>::FractoriumEmberController(Fractorium* fractorium)
{
if (b = InitPaletteList(path))
{
m_SheepTools = unique_ptr<SheepTools<T, float>>(new SheepTools<T, float>(
m_PaletteList.Name(0), new EmberNs::Renderer<T, float>()));
m_SheepTools = make_unique<SheepTools<T, float>>(m_PaletteList.Name(0), new EmberNs::Renderer<T, float>());
break;
}
}
@ -102,9 +89,11 @@ FractoriumEmberController<T>::FractoriumEmberController(Fractorium* fractorium)
if (auto top = tree->topLevelItem(0))
{
for (auto i = start; m_PreviewRun && i < end && i < m_EmberFile.Size(); i++)
size_t i = start;
for (auto b = Advance(m_EmberFile.m_Embers.begin(), start); m_PreviewRun && i < end && b != m_EmberFile.m_Embers.end(); ++b, ++i)
{
Ember<T> ember = m_EmberFile.m_Embers[i];
Ember<T> ember = *b;
ember.SyncSize();
ember.SetSizeAndAdjustScale(PREVIEW_SIZE, PREVIEW_SIZE, false, eScaleType::SCALE_WIDTH);
ember.m_TemporalSamples = 1;
@ -124,7 +113,6 @@ FractoriumEmberController<T>::FractoriumEmberController(Fractorium* fractorium)
Q_ARG(vector<byte>&, m_PreviewFinalImage),
Q_ARG(uint, PREVIEW_SIZE),
Q_ARG(uint, PREVIEW_SIZE));
//treeItem->SetImage(m_PreviewFinalImage, PREVIEW_SIZE, PREVIEW_SIZE);
}
}
}
@ -152,7 +140,7 @@ template <typename T> void FractoriumEmberController<T>::SetEmberFile(const Embe
template <typename T> void FractoriumEmberController<T>::CopyEmberFile(EmberFile<float>& emberFile, std::function<void(Ember<float>& ember)> perEmberOperation)
{
emberFile.m_Filename = m_EmberFile.m_Filename;
CopyVec(emberFile.m_Embers, m_EmberFile.m_Embers, perEmberOperation);
CopyCont(emberFile.m_Embers, m_EmberFile.m_Embers, perEmberOperation);
}
template <typename T> void FractoriumEmberController<T>::SetTempPalette(const Palette<float>& palette) { m_TempPalette = palette; }
@ -164,7 +152,7 @@ template <typename T> void FractoriumEmberController<T>::SetEmberFile(const Embe
template <typename T> void FractoriumEmberController<T>::CopyEmberFile(EmberFile<double>& emberFile, std::function<void(Ember<double>& ember)> perEmberOperation)
{
emberFile.m_Filename = m_EmberFile.m_Filename;
CopyVec(emberFile.m_Embers, m_EmberFile.m_Embers, perEmberOperation);
CopyCont(emberFile.m_Embers, m_EmberFile.m_Embers, perEmberOperation);
}
template <typename T> void FractoriumEmberController<T>::SetTempPalette(const Palette<double>& palette) { m_TempPalette = palette; }
@ -200,7 +188,7 @@ void FractoriumEmberController<T>::SetEmber(size_t index)
}
ClearUndo();
SetEmber(m_EmberFile.m_Embers[index]);
SetEmber(*m_EmberFile.Get(index));
}
}
@ -340,10 +328,10 @@ void FractoriumEmberController<T>::SetEmberPrivate(const Ember<U>& ember, bool v
size_t w = m_Ember.m_FinalRasW;//Cache values for use below.
size_t h = m_Ember.m_FinalRasH;
m_Ember = ember;
m_EmberFilePointer = &ember;
if (!verbatim)
{
//m_Ember.SetSizeAndAdjustScale(m_Fractorium->ui.GLDisplay->width(), m_Fractorium->ui.GLDisplay->height(), true, SCALE_WIDTH);
m_Ember.m_TemporalSamples = 1;//Change once animation is supported.
m_Ember.m_Quality = m_Fractorium->m_QualitySpin->value();
m_Ember.m_Supersample = m_Fractorium->m_SupersampleSpin->value();

View File

@ -18,6 +18,12 @@ enum class eEditUndoState : et { REGULAR_EDIT, UNDO_REDO, EDIT_UNDO };
/// </summary>
enum class eXformUpdate : et { UPDATE_CURRENT, UPDATE_SELECTED, UPDATE_CURRENT_AND_SELECTED, UPDATE_SELECTED_EXCEPT_FINAL, UPDATE_ALL, UPDATE_ALL_EXCEPT_FINAL };
/// <summary>
/// An enum representing the type of synchronizing to do between the list of Embers kept in memory
/// and the widgets in the library tree.
/// </summary>
enum eLibraryUpdate { INDEX = 1, NAME = 2, POINTER = 4 };
/// <summary>
/// FractoriumEmberController and Fractorium need each other, but each can't include the other.
/// So Fractorium includes this file, and Fractorium is declared as a forward declaration here.
@ -42,6 +48,7 @@ class FractoriumEmberControllerBase : public RenderCallback
{
public:
FractoriumEmberControllerBase(Fractorium* fractorium);
FractoriumEmberControllerBase(const FractoriumEmberControllerBase& controller) = delete;
virtual ~FractoriumEmberControllerBase();
//Embers.
@ -107,14 +114,14 @@ public:
//Toolbar.
//Library.
virtual void SyncNames() { }
virtual void SyncPointers() { }
virtual void SyncLibrary(eLibraryUpdate update) { }
virtual void FillLibraryTree(int selectIndex = -1) { }
virtual void UpdateLibraryTree() { }
virtual void EmberTreeItemChanged(QTreeWidgetItem* item, int col) { }
virtual void EmberTreeItemDoubleClicked(QTreeWidgetItem* item, int col) { }
virtual void RenderPreviews(uint start = UINT_MAX, uint end = UINT_MAX) { }
virtual void StopPreviewRender() { }
virtual void MoveLibraryItems(int startRow, int destRow) { }
virtual void Delete(const pair<size_t, QTreeWidgetItem*>& p) { }
//Params.
@ -237,17 +244,17 @@ protected:
eProcessState ProcessState() { return m_Renderer.get() ? m_Renderer->ProcessState() : eProcessState::NONE; }
//Non-templated members.
bool m_Rendering;
bool m_Shared;
bool m_Rendering = false;
bool m_Shared = true;
bool m_LastEditWasUndoRedo;
vector<pair<size_t, size_t>> m_Devices;
size_t m_SubBatchCount;
uint m_FailedRenders;
size_t m_UndoIndex;
double m_LockedScale;
eRendererType m_RenderType;
size_t m_SubBatchCount = 1;//Will be ovewritten by the options on first render.
uint m_FailedRenders = 0;
size_t m_UndoIndex = 0;
double m_LockedScale = 1;
eRendererType m_RenderType = eRendererType::CPU_RENDERER;
eEditUndoState m_EditState;
GLuint m_OutputTexID;
GLuint m_OutputTexID = 0;
Timing m_RenderElapsedTimer;
EmberStats m_Stats;
QImage m_FinalPaletteImage;
@ -265,7 +272,7 @@ protected:
Fractorium* m_Fractorium;
std::unique_ptr<QTimer> m_RenderTimer;
std::unique_ptr<QTimer> m_RenderRestartTimer;
shared_ptr<OpenCLInfo> m_Info;
shared_ptr<OpenCLInfo> m_Info = OpenCLInfo::Instance();
};
/// <summary>
@ -279,6 +286,7 @@ class FractoriumEmberController : public FractoriumEmberControllerBase
{
public:
FractoriumEmberController(Fractorium* fractorium);
FractoriumEmberController(const FractoriumEmberController<T>& controller) = delete;
virtual ~FractoriumEmberController();
//Embers.
@ -347,10 +355,10 @@ public:
//Toolbar.
//Library.
virtual void SyncNames() override;
virtual void SyncPointers() override;
virtual void SyncLibrary(eLibraryUpdate update) override;
virtual void FillLibraryTree(int selectIndex = -1) override;
virtual void UpdateLibraryTree() override;
virtual void MoveLibraryItems(int startRow, int destRow) override;
virtual void Delete(const pair<size_t, QTreeWidgetItem*>& p) override;
virtual void EmberTreeItemChanged(QTreeWidgetItem* item, int col) override;
virtual void EmberTreeItemDoubleClicked(QTreeWidgetItem* item, int col) override;
@ -489,11 +497,12 @@ private:
bool SyncSizes();
//Templated members.
bool m_PreviewRun;
bool m_PreviewRunning;
bool m_PreviewRun = false;
bool m_PreviewRunning = false;
vector<T> m_TempOpacities;
vector<T> m_NormalizedWeights;
Ember<T> m_Ember;
const void* m_EmberFilePointer = nullptr;
EmberFile<T> m_EmberFile;
deque<Ember<T>> m_UndoList;
vector<Xform<T>> m_CopiedXforms;
@ -503,7 +512,7 @@ private:
VariationList<T>& m_VariationList;
unique_ptr<SheepTools<T, float>> m_SheepTools;
unique_ptr<GLEmberController<T>> m_GLController;
unique_ptr<EmberNs::Renderer<T, float>> m_PreviewRenderer;
unique_ptr<EmberNs::Renderer<T, float>> m_PreviewRenderer = make_unique<EmberNs::Renderer<T, float>>();
QFuture<void> m_PreviewResult;
std::function<void (uint, uint)> m_PreviewRenderFunc;
};

View File

@ -6,12 +6,12 @@
/// </summary>
void Fractorium::InitLibraryUI()
{
ui.LibraryTree->SetMainWindow(this);
connect(ui.LibraryTree, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(OnEmberTreeItemChanged(QTreeWidgetItem*, int)), Qt::QueuedConnection);
connect(ui.LibraryTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(OnEmberTreeItemDoubleClicked(QTreeWidgetItem*, int)), Qt::QueuedConnection);
connect(ui.LibraryTree, SIGNAL(itemActivated(QTreeWidgetItem*, int)), this, SLOT(OnEmberTreeItemDoubleClicked(QTreeWidgetItem*, int)), Qt::QueuedConnection);
}
/// <summary>
/// Get the index of the currently selected ember in the library tree.
/// </summary>
@ -52,44 +52,30 @@ void Fractorium::SetLibraryTreeItemData(EmberTreeWidgetItemBase* item, vector<by
/// <summary>
/// Set all libary tree entries to the name of the corresponding ember they represent.
/// </summary>
template <typename T>
void FractoriumEmberController<T>::SyncNames()
{
EmberTreeWidgetItem<T>* item;
auto tree = m_Fractorium->ui.LibraryTree;
tree->blockSignals(true);
if (auto top = tree->topLevelItem(0))
{
for (int i = 0; i < top->childCount(); i++)//Iterate through all of the children, which will represent the open embers.
{
if ((item = dynamic_cast<EmberTreeWidgetItem<T>*>(top->child(i))) && i < m_EmberFile.Size())//Cast the child widget to the EmberTreeWidgetItem type.
item->setText(0, QString::fromStdString(m_EmberFile.m_Embers[i].m_Name));
}
}
tree->blockSignals(false);
}
/// <summary>
/// Set all libary tree entries to point to the underlying ember they represent.
/// </summary>
template <typename T>
void FractoriumEmberController<T>::SyncPointers()
void FractoriumEmberController<T>::SyncLibrary(eLibraryUpdate update)
{
EmberTreeWidgetItem<T>* item;
auto it = m_EmberFile.m_Embers.begin();
auto tree = m_Fractorium->ui.LibraryTree;
tree->blockSignals(true);
if (auto top = tree->topLevelItem(0))
{
size_t childCount = top->childCount();
for (int i = 0; i < childCount; i++)//Iterate through all of the children, which will represent the open embers.
for (int i = 0; i < top->childCount() && it != m_EmberFile.m_Embers.end(); ++i, ++it)//Iterate through all of the children, which will represent the open embers.
{
if ((item = dynamic_cast<EmberTreeWidgetItem<T>*>(top->child(i))) && i < m_EmberFile.Size())//Cast the child widget to the EmberTreeWidgetItem type.
item->SetEmberPointer(&m_EmberFile.m_Embers[i]);
if (auto item = dynamic_cast<EmberTreeWidgetItem<T>*>(top->child(i)))//Cast the child widget to the EmberTreeWidgetItem type.
{
if (update & eLibraryUpdate::INDEX)
it->m_Index = i;
if (update & eLibraryUpdate::NAME)
item->setText(0, QString::fromStdString(it->m_Name));
if (update & eLibraryUpdate::POINTER)
item->SetEmberPointer(&(*it));
}
}
}
@ -105,7 +91,8 @@ void FractoriumEmberController<T>::SyncPointers()
template <typename T>
void FractoriumEmberController<T>::FillLibraryTree(int selectIndex)
{
uint j, size = 64;
uint size = 64;
uint i = 0;
auto tree = m_Fractorium->ui.LibraryTree;
vector<byte> v(size * size * 4);
StopPreviewRender();
@ -116,18 +103,16 @@ void FractoriumEmberController<T>::FillLibraryTree(int selectIndex)
QFileInfo info(m_EmberFile.m_Filename);
fileItem->setText(0, info.fileName());
fileItem->setToolTip(0, m_EmberFile.m_Filename);
fileItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable);
fileItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled);
for (j = 0; j < m_EmberFile.Size(); j++)
for (auto& it : m_EmberFile.m_Embers)
{
auto ember = &m_EmberFile.m_Embers[j];
auto emberItem = new EmberTreeWidgetItem<T>(ember, fileItem);
emberItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable);
auto emberItem = new EmberTreeWidgetItem<T>(&it, fileItem);
if (ember->m_Name.empty())
emberItem->setText(0, ToString(j));
if (it.m_Name.empty())
emberItem->setText(0, ToString(i++));
else
emberItem->setText(0, ember->m_Name.c_str());
emberItem->setText(0, it.m_Name.c_str());
emberItem->setToolTip(0, emberItem->text(0));
emberItem->SetImage(v, size, size);
@ -152,35 +137,33 @@ void FractoriumEmberController<T>::FillLibraryTree(int selectIndex)
template <typename T>
void FractoriumEmberController<T>::UpdateLibraryTree()
{
uint i, size = 64;
auto tree = m_Fractorium->ui.LibraryTree;
uint size = 64;
vector<byte> v(size * size * 4);
auto tree = m_Fractorium->ui.LibraryTree;
if (auto top = tree->topLevelItem(0))
{
int childCount = top->childCount();
int origChildCount = top->childCount();
int i = origChildCount;
tree->blockSignals(true);
for (i = childCount; i < m_EmberFile.Size(); i++)
for (auto it = Advance(m_EmberFile.m_Embers.begin(), i); it != m_EmberFile.m_Embers.end(); ++it)
{
Ember<T>* ember = &m_EmberFile.m_Embers[i];
auto emberItem = new EmberTreeWidgetItem<T>(ember, top);
emberItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable);
auto emberItem = new EmberTreeWidgetItem<T>(&(*it), top);
if (ember->m_Name.empty())
emberItem->setText(0, ToString(i));
if (it->m_Name.empty())
emberItem->setText(0, ToString(i++));
else
emberItem->setText(0, ember->m_Name.c_str());
emberItem->setText(0, it->m_Name.c_str());
emberItem->setToolTip(0, emberItem->text(0));
emberItem->SetImage(v, size, size);
}
//When adding elements to the vector, they may have been reshuffled which will have invalidated
//the pointers contained in the EmberTreeWidgetItems. So reassign all pointers here.
SyncPointers();
//When adding elements, ensure all indices are sequential.
SyncLibrary(eLibraryUpdate::INDEX);
tree->blockSignals(false);
RenderPreviews(childCount, uint(m_EmberFile.Size()));
RenderPreviews(origChildCount, uint(m_EmberFile.Size()));
}
}
@ -200,9 +183,8 @@ void FractoriumEmberController<T>::EmberTreeItemChanged(QTreeWidgetItem* item, i
try
{
auto tree = m_Fractorium->ui.LibraryTree;
auto emberItem = dynamic_cast<EmberTreeWidgetItem<T>*>(item);
if (emberItem)
if (auto emberItem = dynamic_cast<EmberTreeWidgetItem<T>*>(item))
{
if (emberItem->text(0).isEmpty())//Prevent empty string.
{
@ -214,10 +196,10 @@ void FractoriumEmberController<T>::EmberTreeItemChanged(QTreeWidgetItem* item, i
tree->blockSignals(true);
emberItem->UpdateEmberName();//Copy edit text to the ember's name variable.
m_EmberFile.MakeNamesUnique();//Ensure all names remain unique.
SyncNames();//Copy all ember names to the tree items since some might have changed to be made unique.
SyncLibrary(eLibraryUpdate::NAME);//Copy all ember names to the tree items since some might have changed to be made unique.
string newName = emberItem->GetEmber()->m_Name;//Get the new, final, unique name.
if (m_Ember.m_Name == oldName && oldName != newName)//If the ember edited was the current one, and the name was indeed changed, update the name of the current one.
if (m_EmberFilePointer == emberItem->GetEmber() && oldName != newName)//If the ember edited was the current one, and the name was indeed changed, update the name of the current one.
{
m_Ember.m_Name = newName;
m_LastSaveCurrent = "";//Reset will force the dialog to show on the next save current since the user probably wants a different name.
@ -259,6 +241,7 @@ void FractoriumEmberController<T>::EmberTreeItemDoubleClicked(QTreeWidgetItem* i
{
if (auto emberItem = dynamic_cast<EmberTreeWidgetItem<T>*>(item))
{
//qDebug() << "Setting current ember to: " << QString::fromStdString(emberItem->GetEmber()->m_Name);
ClearUndo();
SetEmber(*emberItem->GetEmber());
}
@ -266,6 +249,24 @@ void FractoriumEmberController<T>::EmberTreeItemDoubleClicked(QTreeWidgetItem* i
void Fractorium::OnEmberTreeItemDoubleClicked(QTreeWidgetItem* item, int col) { m_Controller->EmberTreeItemDoubleClicked(item, col); }
/// <summary>
/// Move a library item at one index to the next index.
/// </summary>
/// <param name="startRow">The index of the source item to move</param>
/// <param name="destRow">The destination index to move the item to</param>
template <typename T>
void FractoriumEmberController<T>::MoveLibraryItems(int startRow, int destRow)
{
int i = 0;
auto tree = m_Fractorium->ui.LibraryTree;
auto top = tree->topLevelItem(0);
auto b = m_EmberFile.m_Embers.begin();
auto s = Advance(b, startRow);
auto d = Advance(b, destRow);
m_EmberFile.m_Embers.splice(d, m_EmberFile.m_Embers, s);
SyncLibrary(eLibraryUpdate::INDEX);//Only indices need syncing.
}
/// <summary>
/// Delete the currently selected item in the tree.
/// Note this is not necessarilly the current ember, it's just the item
@ -275,25 +276,18 @@ void Fractorium::OnEmberTreeItemDoubleClicked(QTreeWidgetItem* item, int col) {
template <typename T>
void FractoriumEmberController<T>::Delete(const pair<size_t, QTreeWidgetItem*>& p)
{
auto tree = m_Fractorium->ui.LibraryTree;
tree->blockSignals(true);
if (m_EmberFile.Delete(p.first))
{
delete p.second;
SyncPointers();
SyncLibrary(eLibraryUpdate::INDEX);
}
tree->blockSignals(false);
//If there is now only one item left and it wasn't selected, select it.
if (auto top = tree->topLevelItem(0))
{
if (auto top = m_Fractorium->ui.LibraryTree->topLevelItem(0))
if (top->childCount() == 1)
if (auto item = dynamic_cast<EmberTreeWidgetItem<T>*>(top->child(0)))
if (item->GetEmber()->m_Name != m_Ember.m_Name)
EmberTreeItemDoubleClicked(top->child(0), 0);
}
}
/// <summary>
@ -326,7 +320,7 @@ void FractoriumEmberController<T>::RenderPreviews(uint start, uint end)
if (auto top = tree->topLevelItem(0))
{
int childCount = top->childCount();
vector<byte> emptyPreview(PREVIEW_SIZE * PREVIEW_SIZE * 3);
vector<byte> emptyPreview(PREVIEW_SIZE * PREVIEW_SIZE * 4);
for (int i = 0; i < childCount; i++)
if (auto treeItem = dynamic_cast<EmberTreeWidgetItem<T>*>(top->child(i)))

View File

@ -55,7 +55,6 @@ void FractoriumEmberController<T>::NewFlock(size_t count)
Ember<T> ember;
StopPreviewRender();
m_EmberFile.Clear();
m_EmberFile.m_Embers.reserve(count);
m_EmberFile.m_Filename = EmberFile<T>::DefaultFilename();
for (size_t i = 0; i < count; i++)
@ -206,7 +205,7 @@ void FractoriumEmberController<T>::OpenAndPrepFiles(const QStringList& filenames
}
if (!errors.empty())
m_Fractorium->ErrorReportToQTextEdit(errors, m_Fractorium->ui.InfoFileOpeningTextEdit);
m_Fractorium->ErrorReportToQTextEdit(errors, m_Fractorium->ui.InfoFileOpeningTextEdit, false);//Concat errors from all files.
}
if (append)
@ -216,12 +215,14 @@ void FractoriumEmberController<T>::OpenAndPrepFiles(const QStringList& filenames
m_EmberFile.m_Embers.insert(m_EmberFile.m_Embers.end(), emberFile.m_Embers.begin(), emberFile.m_Embers.end());
}
else
m_EmberFile = emberFile;
else if (emberFile.Size() > 0)//Ensure at least something was read.
m_EmberFile = std::move(emberFile);//Move the temp to avoid creating dupes because we no longer need it.
//Resync indices and names.
for (i = 0; i < m_EmberFile.Size(); i++)
m_EmberFile.m_Embers[i].m_Index = i;
i = 0;
for (auto& it : m_EmberFile.m_Embers)
it.m_Index = i++;
m_EmberFile.MakeNamesUnique();
@ -281,7 +282,7 @@ void FractoriumEmberController<T>::SaveCurrentAsXml()
if (tempEdit)
xmlFreeDoc(tempEdit);
if (writer.Save(filename.toStdString().c_str(), ember, 0, true, false, true))
if (writer.Save(filename.toStdString().c_str(), ember, 0, true, true))
{
s->SaveFolder(fileInfo.canonicalPath());
@ -324,7 +325,7 @@ void FractoriumEmberController<T>::SaveEntireFileAsXml()
for (auto& ember : emberFile.m_Embers)
ApplyXmlSavingTemplate(ember);
if (writer.Save(filename.toStdString().c_str(), emberFile.m_Embers, 0, true, false, true))
if (writer.Save(filename.toStdString().c_str(), emberFile.m_Embers, 0, true, true))
{
if (!s->SaveAutoUnique() || m_LastSaveAll == "")//Only save filename on first time through when doing auto unique names.
m_LastSaveAll = filename;
@ -349,7 +350,7 @@ void Fractorium::OnActionSaveCurrentScreen(bool checked)
auto& pixels = *m_Controller->FinalImage();
auto rendererCL = dynamic_cast<RendererCLBase*>(m_Controller->Renderer());
auto stats = m_Controller->Stats();
auto comments = renderer->ImageComments(stats, 0, false, true);
auto comments = renderer->ImageComments(stats, 0, true);
if (rendererCL && renderer->PrepFinalAccumVector(pixels))
{
@ -370,18 +371,19 @@ void Fractorium::OnActionSaveCurrentScreen(bool checked)
template <typename T>
void FractoriumEmberController<T>::SaveCurrentToOpenedFile()
{
uint i;
uint i = 0;
bool fileFound = false;
for (i = 0; i < m_EmberFile.Size(); i++)
for (auto& it : m_EmberFile.m_Embers)
{
if ((m_Ember.m_Name == m_EmberFile.m_Embers[i].m_Name) &&//Check both to be extra sure.
(m_Ember.m_Index == m_EmberFile.m_Embers[i].m_Index))
if (&it == m_EmberFilePointer)//Just compare memory addresses.
{
m_EmberFile.m_Embers[i] = m_Ember;
it = m_Ember;//Save it to the opened file in memory.
fileFound = true;
break;
}
i++;
}
if (!fileFound)
@ -470,7 +472,7 @@ void FractoriumEmberController<T>::CopyXml()
ember.m_Quality = settings->XmlQuality();
ember.m_Supersample = settings->XmlSupersample();
ember.m_TemporalSamples = settings->XmlTemporalSamples();
QApplication::clipboard()->setText(QString::fromStdString(emberToXml.ToString(ember, "", 0, false, false, true)));
QApplication::clipboard()->setText(QString::fromStdString(emberToXml.ToString(ember, "", 0, false, true)));
}
void Fractorium::OnActionCopyXml(bool checked) { m_Controller->CopyXml(); }
@ -490,7 +492,7 @@ void FractoriumEmberController<T>::CopyAllXml()
{
Ember<T> ember = e;
ApplyXmlSavingTemplate(ember);
os << emberToXml.ToString(ember, "", 0, false, false, true);
os << emberToXml.ToString(ember, "", 0, false, true);
}
os << "</flames>\n";
@ -563,9 +565,10 @@ void Fractorium::OnActionPasteXmlAppend(bool checked) { m_Controller->PasteXmlAp
template <typename T>
void FractoriumEmberController<T>::PasteXmlOver()
{
size_t i = 0;
string s, errors;
XmlToEmber<T> parser;
auto backupEmber = m_EmberFile.m_Embers[0];
auto backupEmber = m_EmberFile.m_Embers.begin();
auto codec = QTextCodec::codecForName("UTF-8");
auto b = codec->fromUnicode(QApplication::clipboard()->text());
s.reserve(b.size());
@ -589,20 +592,20 @@ void FractoriumEmberController<T>::PasteXmlOver()
if (m_EmberFile.Size())
{
for (auto i = 0; i < m_EmberFile.Size(); i++)
for (auto it : m_EmberFile.m_Embers)
{
m_EmberFile.m_Embers[i].m_Index = i;
ConstrainDimensions(m_EmberFile.m_Embers[i]);//Do not exceed the max texture size.
it.m_Index = i++;
ConstrainDimensions(it);//Do not exceed the max texture size.
//Also ensure it has a name.
if (m_EmberFile.m_Embers[i].m_Name == "" || m_EmberFile.m_Embers[i].m_Name == "No name")
m_EmberFile.m_Embers[i].m_Name = ToString<qulonglong>(m_EmberFile.m_Embers[i].m_Index).toStdString();
if (it.m_Name == "" || it.m_Name == "No name")
it.m_Name = ToString<qulonglong>(it.m_Index).toStdString();
}
}
else
{
backupEmber.m_Index = 0;
m_EmberFile.m_Embers.push_back(backupEmber);
backupEmber->m_Index = 0;
m_EmberFile.m_Embers.push_back(*backupEmber);
}
m_EmberFile.MakeNamesUnique();

View File

@ -11,12 +11,6 @@ GLWidget::GLWidget(QWidget* p)
: QOpenGLWidget(p)
{
QSurfaceFormat qsf;
m_Init = false;
m_Drawing = false;
m_TexWidth = 0;
m_TexHeight = 0;
m_OutputTexID = 0;
m_Fractorium = nullptr;
qsf.setSwapInterval(1);//Vsync.
qsf.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
qsf.setVersion(2, 0);

View File

@ -73,13 +73,13 @@ private:
void DrawAffineHelper(int index, bool selected, bool pre, bool final, bool background);
GLEmberControllerBase* GLController();
bool m_Init;
bool m_Drawing;
GLint m_MaxTexSize;
GLint m_TexWidth;
GLint m_TexHeight;
GLint m_ViewWidth;
GLint m_ViewHeight;
GLuint m_OutputTexID;
Fractorium* m_Fractorium;
bool m_Init = false;
bool m_Drawing = false;
GLint m_MaxTexSize = 16384;
GLint m_TexWidth = 0;
GLint m_TexHeight = 0;
GLint m_ViewWidth = 0;
GLint m_ViewHeight = 0;
GLuint m_OutputTexID = 0;
Fractorium* m_Fractorium = nullptr;
};

View File

@ -0,0 +1,40 @@
#include "FractoriumPch.h"
#include "LibraryTreeWidget.h"
#include "Fractorium.h"
/// <summary>
/// Set a pointer to the main window.
/// </summary>
/// <param name="f">Pointer to the main Fractorium object</param>
void LibraryTreeWidget::SetMainWindow(Fractorium* f)
{
m_Fractorium = f;
}
/// <summary>
/// Process the drop event to allow for moving items around inside of the tree.
/// </summary>
/// <param name="de">Pointer to the QDropEvent object</param>
void LibraryTreeWidget::dropEvent(QDropEvent* de)
{
QModelIndex droppedIndex = indexAt(de->pos());
auto items = selectionModel()->selectedIndexes();
if (!droppedIndex.isValid())//Don't process drop because it's outside of the droppable area.
{
de->ignore();
return;
}
else if (!items.empty())//Actually do the drop and move the item to a new location.
{
int row = droppedIndex.row();
DropIndicatorPosition dp = dropIndicatorPosition();
if (dp == QAbstractItemView::BelowItem)
row++;
m_Fractorium->m_Controller->MoveLibraryItems(items[0].row(), row);
}
QTreeWidget::dropEvent(de);
}

View File

@ -0,0 +1,29 @@
#pragma once
#include "FractoriumPch.h"
class Fractorium;
/// <summary>
/// A thin derivation of QTreeWidget which allows for processing the drop event.
/// </summary>
class LibraryTreeWidget : public QTreeWidget
{
Q_OBJECT
public:
/// <summary>
/// Constructor that passes p to the parent.
/// </summary>
/// <param name="p">The parent widget</param>
explicit LibraryTreeWidget(QWidget* p = nullptr)
: QTreeWidget(p)
{
}
void SetMainWindow(Fractorium* f);
protected:
virtual void dropEvent(QDropEvent* de) override;
Fractorium* m_Fractorium = nullptr;
};

View File

@ -24,7 +24,7 @@ class FractoriumOptionsDialog : public QDialog
friend Fractorium;
public:
FractoriumOptionsDialog(FractoriumSettings* settings, QWidget* p = 0, Qt::WindowFlags f = 0);
FractoriumOptionsDialog(FractoriumSettings* settings, QWidget* p = nullptr, Qt::WindowFlags f = 0);
public slots:
void OnOpenCLCheckBoxStateChanged(int state);

View File

@ -16,7 +16,7 @@ class SpinBox : public QSpinBox
Q_OBJECT
public:
explicit SpinBox(QWidget* p = 0, int height = 16, int step = 1);
explicit SpinBox(QWidget* p = nullptr, int height = 16, int step = 1);
virtual ~SpinBox() { }
void SetValueStealth(int d);
void SetValueStealth(size_t d);

View File

@ -15,8 +15,8 @@ class StealthComboBox : public QComboBox
Q_OBJECT
public:
explicit StealthComboBox(QWidget* p = 0) : QComboBox(p) { }
explicit StealthComboBox(QWidget* p = nullptr) : QComboBox(p) { }
/// <summary>
/// Set the current index of the combo box without triggering signals.
/// </summary>

View File

@ -24,14 +24,14 @@
/// </summary>
class TableWidget : public QTableWidget
{
Q_OBJECT
Q_OBJECT
public:
/// <summary>
/// Constructor that passes the parent to the base and installs
/// the event filter.
/// </summary>
/// <param name="p">The parent widget</param>
explicit TableWidget(QWidget* p = 0)
explicit TableWidget(QWidget* p = nullptr)
: QTableWidget(p)
{
viewport()->installEventFilter(this);
@ -46,7 +46,7 @@ protected:
/// <returns>True if mouse wheel, else return the result of calling the base fucntion.</returns>
bool eventFilter(QObject* obj, QEvent* e)
{
if(e->type() == QEvent::Wheel)
if (e->type() == QEvent::Wheel)
{
e->ignore();
return true;

View File

@ -22,7 +22,7 @@ public:
/// </summary>
/// <param name="id">The ID of the variation this widget will represent</param>
/// <param name="p">The parent widget</param>
VariationTreeWidgetItem(eVariationId id, QTreeWidget* p = 0)
VariationTreeWidgetItem(eVariationId id, QTreeWidget* p = nullptr)
: QTreeWidgetItem(p)
{
m_Id = id;