0.4.1.3 Beta 10/14/2014

--User Changes
 Size is no longer fixed to the window size.
 Size scaling is done differently in the final render dialog. This fixes several bugs.
 Remove Xml saving size from settings and options dialog, it no longer applies.
 Final render can be broken into strips.
 Set default save path to the desktop if none is found in the settings file.
 Set default output size to 1920x1080 if none is found in the settings file.

--Bug Fixes
 Better memory size reporting in final render dialog.

--Code Changes
 Migrate to C++11, Qt 5.3.1, and Visual Studio 2013.
 Change most instances of unsigned int to size_t, and int to intmax_t.
 Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes.
 Replace some sprintf_s() calls in XmlToEmber with ostringstream.
 Move more non-templated members into RendererBase.
 Add CopyVec() overload that takes a per element function pointer.
 Add vector Memset().
 Replace '&' with '+' instead of "&" in XmlToEmber for much faster parsing.
 Break strips rendering out into EmberCommon and call from EmberRender and Fractorium.
 Make AddAndWriteBuffer() just call WriteBuffer().
 Make AddAndWriteImage() delete the existing image first before replacing it.
 Add SetOutputTexture() to RendererCL to support making new textures in response to resize events.
 Remove multiple return statements in RendererCL, and replace with a bool that tracks results.
 Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium.
 Add Size() wrapper in EmberFile.
 Make QString function arguments const QString&, and string with const string&.
 Make ShowCritical() wrapper for invoking a message box from another thread.
 Add combo box to TwoButtonWidget and rename.
This commit is contained in:
mfeemster
2014-10-14 08:53:15 -07:00
parent 44c90abb32
commit 9e94170a70
80 changed files with 4358 additions and 3661 deletions

View File

@ -76,6 +76,14 @@ public:
m_Embers.clear();
}
/// <summary>
/// Thin wrapper to get the size of the vector of embers.
/// </summary>
size_t Size()
{
return m_Embers.size();
}
/// <summary>
/// Ensure all ember names are unique.
/// </summary>
@ -89,7 +97,7 @@ public:
{
if (i != j && m_Embers[i].m_Name == m_Embers[j].m_Name)
{
m_Embers[j].m_Name = m_Embers[j].m_Name + "_" + QString::number(++x).toStdString();
m_Embers[j].m_Name = m_Embers[j].m_Name + "_" + ToString(++x).toStdString();
j = 0;
}
}
@ -109,7 +117,7 @@ public:
/// Ensures a given input filename is unique by appending a count to the end.
/// </summary>
/// <returns>The passed in name if it was unique, else a uniquely made name.</returns>
static QString UniqueFilename(QString& filename)
static QString UniqueFilename(const QString& filename)
{
if (!QFile::exists(filename))
return filename;
@ -117,13 +125,13 @@ public:
int counter = 2;
QString newPath;
QFileInfo original(filename);
QString path = original.absolutePath() + QDir::separator();
QString path = original.absolutePath() + '/';
QString base = original.completeBaseName();
QString extension = original.suffix();
do
{
newPath = path + base + "_" + QString::number(counter++) + "." + extension;
newPath = path + base + "_" + ToString(counter++) + "." + extension;
}
while (QFile::exists(newPath));
@ -138,7 +146,7 @@ public:
/// <returns>The default ember name</returns>
static QString DefaultEmberName(unsigned int i)
{
return DefaultFilename() + "-" + QString::number(i);
return DefaultFilename() + "-" + ToString(i);
}
QString m_Filename;

View File

@ -18,7 +18,7 @@ FractoriumFinalRenderDialog::FractoriumFinalRenderDialog(FractoriumSettings* set
int row = 0, spinHeight = 20;
unsigned int i;
double dmax = numeric_limits<double>::max();
QTableWidget* table = ui.FinalRenderGeometryTable;
QTableWidget* table = ui.FinalRenderParamsTable;
QTableWidgetItem* item = NULL;
m_Fractorium = (Fractorium*)parent;
@ -31,30 +31,51 @@ FractoriumFinalRenderDialog::FractoriumFinalRenderDialog(FractoriumSettings* set
connect(ui.FinalRenderDoublePrecisionCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnDoublePrecisionCheckBoxStateChanged(int)), Qt::QueuedConnection);
connect(ui.FinalRenderPlatformCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(OnPlatformComboCurrentIndexChanged(int)), Qt::QueuedConnection);
connect(ui.FinalRenderDoAllCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnDoAllCheckBoxStateChanged(int)), Qt::QueuedConnection);
connect(ui.FinalRenderDoSequenceCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnDoSequenceCheckBoxStateChanged(int)), Qt::QueuedConnection);
connect(ui.FinalRenderCurrentSpin, SIGNAL(valueChanged(int)), this, SLOT(OnFinalRenderCurrentSpinChanged(int)), Qt::QueuedConnection);
connect(ui.FinalRenderApplyToAllCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnApplyAllCheckBoxStateChanged(int)), Qt::QueuedConnection);
connect(ui.FinalRenderKeepAspectCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnKeepAspectCheckBoxStateChanged(int)), Qt::QueuedConnection);
connect(ui.FinalRenderScaleNoneRadioButton, SIGNAL(toggled(bool)), this, SLOT(OnScaleRadioButtonChanged(bool)), Qt::QueuedConnection);
connect(ui.FinalRenderScaleWidthRadioButton, SIGNAL(toggled(bool)), this, SLOT(OnScaleRadioButtonChanged(bool)), Qt::QueuedConnection);
connect(ui.FinalRenderScaleHeightRadioButton, SIGNAL(toggled(bool)), this, SLOT(OnScaleRadioButtonChanged(bool)), Qt::QueuedConnection);
SetupSpinner<DoubleSpinBox, double>(ui.FinalRenderSizeTable, this, row, 1, m_WidthScaleSpin, spinHeight, 0.001, 99.99, 0.1, SIGNAL(valueChanged(double)), SLOT(OnFinalRenderWidthScaleChanged(double)), true, 1.0, 1.0, 1.0);
SetupSpinner<DoubleSpinBox, double>(ui.FinalRenderSizeTable, this, row, 1, m_HeightScaleSpin, spinHeight, 0.001, 99.99, 0.1, SIGNAL(valueChanged(double)), SLOT(OnFinalRenderHeightScaleChanged(double)), true, 1.0, 1.0, 1.0);
m_WidthScaleSpin->setDecimals(3);
m_HeightScaleSpin->setDecimals(3);
m_WidthScaleSpin->setSuffix(" ( )");
m_HeightScaleSpin->setSuffix(" ( )");
m_WidthScaleSpin->SmallStep(0.001);
m_HeightScaleSpin->SmallStep(0.001);
SetupSpinner<SpinBox, int> (table, this, row, 1, m_WidthSpin, spinHeight, 10, 100000, 50, SIGNAL(valueChanged(int)), SLOT(OnWidthChanged(int)), true, 1980);
SetupSpinner<SpinBox, int> (table, this, row, 1, m_HeightSpin, spinHeight, 10, 100000, 50, SIGNAL(valueChanged(int)), SLOT(OnHeightChanged(int)), true, 1080);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_QualitySpin, spinHeight, 1, dmax, 50, SIGNAL(valueChanged(double)), SLOT(OnQualityChanged(double)), true, 1000);
SetupSpinner<SpinBox, int> (table, this, row, 1, m_TemporalSamplesSpin, spinHeight, 1, 5000, 50, SIGNAL(valueChanged(int)), SLOT(OnTemporalSamplesChanged(int)), true, 1000);
SetupSpinner<SpinBox, int> (table, this, row, 1, m_SupersampleSpin, spinHeight, 1, 4, 1, SIGNAL(valueChanged(int)), SLOT(OnSupersampleChanged(int)), true, 2);
row = 0;
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_QualitySpin, spinHeight, 1, dmax, 50, SIGNAL(valueChanged(double)), SLOT(OnQualityChanged(double)), true, 1000, 1000, 1000);
SetupSpinner<SpinBox, int> (table, this, row, 1, m_TemporalSamplesSpin, spinHeight, 1, 5000, 50, SIGNAL(valueChanged(int)), SLOT(OnTemporalSamplesChanged(int)), true, 1000, 1000, 1000);
SetupSpinner<SpinBox, int> (table, this, row, 1, m_SupersampleSpin, spinHeight, 1, 4, 1, SIGNAL(valueChanged(int)), SLOT(OnSupersampleChanged(int)), true, 2, 1, 1);
SetupSpinner<SpinBox, int> (table, this, row, 1, m_StripsSpin, spinHeight, 1, 64, 1, SIGNAL(valueChanged(int)), SLOT(OnStripsChanged(int)), true, 1, 1, 1);
row++;//Memory usage.
m_MemoryCellIndex = row++;//Memory usage.
m_PathCellIndex = row;
TwoButtonWidget* tbw = new TwoButtonWidget("...", "Open", 22, 40, 22, table);
table->setCellWidget(row, 1, tbw);
QStringList comboList;
comboList.append("jpg");
comboList.append("png");
m_Tbcw = new TwoButtonComboWidget("...", "Open", comboList, 22, 40, 22, table);
table->setCellWidget(row, 1, m_Tbcw);
table->item(row++, 1)->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
connect(tbw->m_Button1, SIGNAL(clicked(bool)), this, SLOT(OnFileButtonClicked(bool)), Qt::QueuedConnection);
connect(tbw->m_Button2, SIGNAL(clicked(bool)), this, SLOT(OnShowFolderButtonClicked(bool)), Qt::QueuedConnection);
connect(m_Tbcw->m_Button1, SIGNAL(clicked(bool)), this, SLOT(OnFileButtonClicked(bool)), Qt::QueuedConnection);
connect(m_Tbcw->m_Button2, SIGNAL(clicked(bool)), this, SLOT(OnShowFolderButtonClicked(bool)), Qt::QueuedConnection);
connect(m_Tbcw->m_Combo, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFinalRenderExtIndexChanged(int)), Qt::QueuedConnection);
m_PrefixEdit = new QLineEdit(table);
table->setCellWidget(row++, 1, m_PrefixEdit);
m_SuffixEdit = new QLineEdit(table);
table->setCellWidget(row++, 1, m_SuffixEdit);
connect(m_PrefixEdit, SIGNAL(textChanged(const QString&)), this, SLOT(OnFinalRenderPrefixChanged(const QString&)), Qt::QueuedConnection);
connect(m_SuffixEdit, SIGNAL(textChanged(const QString&)), this, SLOT(OnFinalRenderSuffixChanged(const QString&)), Qt::QueuedConnection);
ui.StartRenderButton->disconnect(SIGNAL(clicked(bool)));
connect(ui.StartRenderButton, SIGNAL(clicked(bool)), this, SLOT(OnRenderClicked(bool)), Qt::QueuedConnection);
@ -97,22 +118,22 @@ FractoriumFinalRenderDialog::FractoriumFinalRenderDialog(FractoriumSettings* set
ui.FinalRenderKeepAspectCheckBox->setChecked( m_Settings->FinalKeepAspect());
ui.FinalRenderThreadCountSpin->setValue( m_Settings->FinalThreadCount());
m_WidthSpin->setValue(m_Settings->FinalWidth());
m_HeightSpin->setValue(m_Settings->FinalHeight());
m_QualitySpin->setValue(m_Settings->FinalQuality());
m_TemporalSamplesSpin->setValue(m_Settings->FinalTemporalSamples());
m_SupersampleSpin->setValue(m_Settings->FinalSupersample());
m_StripsSpin->setValue(m_Settings->FinalStrips());
Scale((eScaleType)m_Settings->FinalScale());
if (m_Settings->FinalDoAllExt() == "jpg")
ui.FinalRenderJpgRadioButton->setChecked(true);
if (m_Settings->FinalExt() == "jpg")
m_Tbcw->m_Combo->setCurrentIndex(0);
else
ui.FinalRenderPngRadioButton->setChecked(true);
m_Tbcw->m_Combo->setCurrentIndex(1);
//Explicitly call these to enable/disable the appropriate controls.
OnOpenCLCheckBoxStateChanged(ui.FinalRenderOpenCLCheckBox->isChecked());
OnDoAllCheckBoxStateChanged(ui.FinalRenderDoAllCheckBox->isChecked());
OnDoSequenceCheckBoxStateChanged(ui.FinalRenderDoSequenceCheckBox->isChecked());
QSize s = size();
int desktopHeight = qApp->desktop()->availableGeometry().height();
@ -122,29 +143,32 @@ FractoriumFinalRenderDialog::FractoriumFinalRenderDialog(FractoriumSettings* set
QWidget* w = SetTabOrder(this, ui.FinalRenderEarlyClipCheckBox, ui.FinalRenderYAxisUpCheckBox);
//Update these with new controls.
w = SetTabOrder(this, w, ui.FinalRenderTransparencyCheckBox);
w = SetTabOrder(this, w, ui.FinalRenderOpenCLCheckBox);
w = SetTabOrder(this, w, ui.FinalRenderDoublePrecisionCheckBox);
w = SetTabOrder(this, w, ui.FinalRenderSaveXmlCheckBox);
w = SetTabOrder(this, w, ui.FinalRenderDoAllCheckBox);
w = SetTabOrder(this, w, ui.FinalRenderDoSequenceCheckBox);
w = SetTabOrder(this, w, ui.FinalRenderKeepAspectCheckBox);
w = SetTabOrder(this, w, ui.FinalRenderScaleNoneRadioButton);
w = SetTabOrder(this, w, ui.FinalRenderScaleWidthRadioButton);
w = SetTabOrder(this, w, ui.FinalRenderScaleHeightRadioButton);
w = SetTabOrder(this, w, ui.FinalRenderJpgRadioButton);
w = SetTabOrder(this, w, ui.FinalRenderPngRadioButton);
w = SetTabOrder(this, w, ui.FinalRenderCurrentSpin);
w = SetTabOrder(this, w, ui.FinalRenderPlatformCombo);
w = SetTabOrder(this, w, ui.FinalRenderDeviceCombo);
w = SetTabOrder(this, w, ui.FinalRenderThreadCountSpin);
w = SetTabOrder(this, w, m_WidthSpin);
w = SetTabOrder(this, w, m_HeightSpin);
w = SetTabOrder(this, w, ui.FinalRenderApplyToAllCheckBox);
w = SetTabOrder(this, w, m_WidthScaleSpin);
w = SetTabOrder(this, w, m_HeightScaleSpin);
w = SetTabOrder(this, w, ui.FinalRenderScaleNoneRadioButton);
w = SetTabOrder(this, w, ui.FinalRenderScaleWidthRadioButton);
w = SetTabOrder(this, w, ui.FinalRenderScaleHeightRadioButton);
w = SetTabOrder(this, w, ui.FinalRenderKeepAspectCheckBox);
w = SetTabOrder(this, w, m_QualitySpin);
w = SetTabOrder(this, w, m_TemporalSamplesSpin);
w = SetTabOrder(this, w, m_SupersampleSpin);
w = SetTabOrder(this, w, tbw);
w = SetTabOrder(this, w, tbw->m_Button1);
w = SetTabOrder(this, w, tbw->m_Button2);
w = SetTabOrder(this, w, m_StripsSpin);
w = SetTabOrder(this, w, m_Tbcw);
w = SetTabOrder(this, w, m_Tbcw->m_Combo);
w = SetTabOrder(this, w, m_Tbcw->m_Button1);
w = SetTabOrder(this, w, m_Tbcw->m_Button2);
w = SetTabOrder(this, w, m_PrefixEdit);
w = SetTabOrder(this, w, m_SuffixEdit);
w = SetTabOrder(this, w, ui.FinalRenderTextOutput);
@ -166,19 +190,22 @@ bool FractoriumFinalRenderDialog::SaveXml() { return ui.FinalRenderSaveXmlCheckB
bool FractoriumFinalRenderDialog::DoAll() { return ui.FinalRenderDoAllCheckBox->isChecked(); }
bool FractoriumFinalRenderDialog::DoSequence() { return ui.FinalRenderDoSequenceCheckBox->isChecked(); }
bool FractoriumFinalRenderDialog::KeepAspect() { return ui.FinalRenderKeepAspectCheckBox->isChecked(); }
QString FractoriumFinalRenderDialog::DoAllExt() { return ui.FinalRenderJpgRadioButton->isChecked() ? "jpg" : "png"; }
QString FractoriumFinalRenderDialog::Path() { return ui.FinalRenderGeometryTable->item(6, 1)->text(); }
void FractoriumFinalRenderDialog::Path(QString s) { ui.FinalRenderGeometryTable->item(6, 1)->setText(s); }
bool FractoriumFinalRenderDialog::ApplyToAll() { return ui.FinalRenderApplyToAllCheckBox->isChecked(); }
QString FractoriumFinalRenderDialog::Ext() { return m_Tbcw->m_Combo->currentIndex() == 0 ? "jpg" : "png"; }
QString FractoriumFinalRenderDialog::Path() { return ui.FinalRenderParamsTable->item(m_PathCellIndex, 1)->text(); }
void FractoriumFinalRenderDialog::Path(const QString& s) { ui.FinalRenderParamsTable->item(m_PathCellIndex, 1)->setText(s); }
QString FractoriumFinalRenderDialog::Prefix() { return m_PrefixEdit->text(); }
QString FractoriumFinalRenderDialog::Suffix() { return m_SuffixEdit->text(); }
unsigned int FractoriumFinalRenderDialog::Current() { return ui.FinalRenderCurrentSpin->value(); }
unsigned int FractoriumFinalRenderDialog::PlatformIndex() { return ui.FinalRenderPlatformCombo->currentIndex(); }
unsigned int FractoriumFinalRenderDialog::DeviceIndex() { return ui.FinalRenderDeviceCombo->currentIndex(); }
unsigned int FractoriumFinalRenderDialog::ThreadCount() { return ui.FinalRenderThreadCountSpin->value(); }
unsigned int FractoriumFinalRenderDialog::Width() { return m_WidthSpin->value(); }
unsigned int FractoriumFinalRenderDialog::Height() { return m_HeightSpin->value(); }
double FractoriumFinalRenderDialog::WidthScale() { return m_WidthScaleSpin->value(); }
double FractoriumFinalRenderDialog::HeightScale() { return m_HeightScaleSpin->value(); }
double FractoriumFinalRenderDialog::Quality() { return m_QualitySpin->value(); }
unsigned int FractoriumFinalRenderDialog::TemporalSamples() { return m_TemporalSamplesSpin->value(); }
unsigned int FractoriumFinalRenderDialog::Supersample() { return m_SupersampleSpin->value(); }
unsigned int FractoriumFinalRenderDialog::Strips() { return m_StripsSpin->value(); }
/// <summary>
/// Capture the current state of the Gui.
@ -200,17 +227,18 @@ FinalRenderGuiState FractoriumFinalRenderDialog::State()
state.m_KeepAspect = KeepAspect();
state.m_Scale = Scale();
state.m_Path = Path();
state.m_DoAllExt = DoAllExt();
state.m_Ext = Ext();
state.m_Prefix = Prefix();
state.m_Suffix = Suffix();
state.m_PlatformIndex = PlatformIndex();
state.m_DeviceIndex = DeviceIndex();
state.m_ThreadCount = ThreadCount();
state.m_Width = Width();
state.m_Height = Height();
state.m_WidthScale = WidthScale();
state.m_HeightScale = HeightScale();
state.m_Quality = Quality();
state.m_TemporalSamples = TemporalSamples();
state.m_Supersample = Supersample();
state.m_Strips = Strips();
return state;
}
@ -237,6 +265,8 @@ eScaleType FractoriumFinalRenderDialog::Scale()
/// <param name="scale">The type of scaling to use</param>
void FractoriumFinalRenderDialog::Scale(eScaleType scale)
{
ui.FinalRenderScaleNoneRadioButton->blockSignals(true);
if (scale == SCALE_NONE)
ui.FinalRenderScaleNoneRadioButton->setChecked(true);
else if (scale == SCALE_WIDTH)
@ -245,6 +275,8 @@ void FractoriumFinalRenderDialog::Scale(eScaleType scale)
ui.FinalRenderScaleHeightRadioButton->setChecked(true);
else
ui.FinalRenderScaleNoneRadioButton->setChecked(true);
ui.FinalRenderScaleNoneRadioButton->blockSignals(false);
}
/// <summary>
@ -307,6 +339,39 @@ void FractoriumFinalRenderDialog::OnDoublePrecisionCheckBoxStateChanged(int stat
SetMemory();
}
/// <summary>
/// The do all checkbox was changed.
/// If checked, render all embers available in the currently opened file, else
/// only render the current ember.
/// </summary>
/// <param name="state">The state of the checkbox</param>
void FractoriumFinalRenderDialog::OnDoAllCheckBoxStateChanged(int state)
{
ui.FinalRenderDoSequenceCheckBox->setEnabled(ui.FinalRenderDoAllCheckBox->isChecked());
}
/// <summary>
/// The do sequence checkbox was changed.
/// If checked, render all embers available in the currently opened file as an animation sequence, else
/// render them individually.
/// </summary>
/// <param name="state">The state of the checkbox</param>
void FractoriumFinalRenderDialog::OnDoSequenceCheckBoxStateChanged(int state)
{
m_TemporalSamplesSpin->setEnabled(ui.FinalRenderDoSequenceCheckBox->isChecked());
}
/// <summary>
/// The current ember spinner was changed, update fields.
/// </summary>
/// <param name="d">Ignored</param>
void FractoriumFinalRenderDialog::OnFinalRenderCurrentSpinChanged(int d)
{
m_Controller->SetEmber(d - 1);
m_Controller->SyncCurrentToGui();
SetMemory();
}
/// <summary>
/// Populate the the device combo box with all available
/// OpenCL devices for the selected platform.
@ -324,15 +389,44 @@ void FractoriumFinalRenderDialog::OnPlatformComboCurrentIndexChanged(int index)
}
/// <summary>
/// The do all checkbox was changed.
/// If checked, render all embers available in the currently opened file, else
/// only render the current ember.
/// The apply all checkbox was changed.
/// If checked, set values for all embers in the file to the values specified in the GUI.
/// </summary>
/// <param name="state">The state of the checkbox</param>
void FractoriumFinalRenderDialog::OnDoAllCheckBoxStateChanged(int state)
void FractoriumFinalRenderDialog::OnApplyAllCheckBoxStateChanged(int state)
{
ui.FinalRenderDoSequenceCheckBox->setEnabled(ui.FinalRenderDoAllCheckBox->isChecked());
ui.FinalRenderExtensionGroupBox->setEnabled(ui.FinalRenderDoAllCheckBox->isChecked());
if (state && m_Controller.get())
m_Controller->SyncGuiToEmbers();
}
/// <summary>
/// The width spinner was changed, recompute required memory.
/// If the aspect ratio checkbox is checked, set the value of
/// the height spinner as well to be in proportion.
/// </summary>
/// <param name="d">Ignored</param>
void FractoriumFinalRenderDialog::OnFinalRenderWidthScaleChanged(double d)
{
if (ui.FinalRenderKeepAspectCheckBox->isChecked() && m_Controller.get())
m_HeightScaleSpin->SetValueStealth(m_WidthScaleSpin->value());
if (SetMemory())
m_Controller->SyncCurrentToSizeSpinners(false, true);
}
/// <summary>
/// The height spinner was changed, recompute required memory.
/// If the aspect ratio checkbox is checked, set the value of
/// the width spinner as well to be in proportion.
/// </summary>
/// <param name="d">Ignored</param>
void FractoriumFinalRenderDialog::OnFinalRenderHeightScaleChanged(double d)
{
if (ui.FinalRenderKeepAspectCheckBox->isChecked() && m_Controller.get())
m_WidthScaleSpin->SetValueStealth(m_HeightScaleSpin->value());
if (SetMemory())
m_Controller->SyncCurrentToSizeSpinners(false, true);
}
/// <summary>
@ -343,7 +437,7 @@ void FractoriumFinalRenderDialog::OnDoAllCheckBoxStateChanged(int state)
void FractoriumFinalRenderDialog::OnKeepAspectCheckBoxStateChanged(int state)
{
if (state && m_Controller.get())
m_HeightSpin->SetValueStealth(m_WidthSpin->value() / m_Controller->OriginalAspect());
m_HeightScaleSpin->SetValueStealth(m_WidthScaleSpin->value());
SetMemory();
}
@ -358,34 +452,6 @@ void FractoriumFinalRenderDialog::OnScaleRadioButtonChanged(bool checked)
SetMemory();
}
/// <summary>
/// The width spinner was changed, recompute required memory.
/// If the aspect ratio checkbox is checked, set the value of
/// the height spinner as well to be in proportion.
/// </summary>
/// <param name="d">Ignored</param>
void FractoriumFinalRenderDialog::OnWidthChanged(int d)
{
if (ui.FinalRenderKeepAspectCheckBox->isChecked() && m_Controller.get())
m_HeightSpin->SetValueStealth(m_WidthSpin->value() / m_Controller->OriginalAspect());
SetMemory();
}
/// <summary>
/// The height spinner was changed, recompute required memory.
/// If the aspect ratio checkbox is checked, set the value of
/// the width spinner as well to be in proportion.
/// </summary>
/// <param name="d">Ignored</param>
void FractoriumFinalRenderDialog::OnHeightChanged(int d)
{
if (ui.FinalRenderKeepAspectCheckBox->isChecked() && m_Controller.get())
m_WidthSpin->SetValueStealth(m_HeightSpin->value() * m_Controller->OriginalAspect());
SetMemory();
}
/// <summary>
/// The quality spinner was changed, recompute required memory.
/// </summary>
@ -413,6 +479,15 @@ void FractoriumFinalRenderDialog::OnSupersampleChanged(int d)
SetMemory();
}
/// <summary>
/// The supersample spinner was changed, recompute required memory.
/// </summary>
/// <param name="d">Ignored</param>
void FractoriumFinalRenderDialog::OnStripsChanged(int d)
{
SetMemory();
}
/// <summary>
/// If a single ember is being rendered, show the save file dialog.
/// If a more than one is being rendered, show the save folder dialog.
@ -422,26 +497,12 @@ void FractoriumFinalRenderDialog::OnSupersampleChanged(int d)
void FractoriumFinalRenderDialog::OnFileButtonClicked(bool checked)
{
bool doAll = ui.FinalRenderDoAllCheckBox->isChecked();
QString filename;
if (doAll)
filename = m_Fractorium->SetupSaveFolderDialog();
else
filename = m_Fractorium->SetupSaveImageDialog(m_Controller->Name());
QString s = m_Fractorium->SetupSaveFolderDialog();
if (filename != "")
if (Exists(s))
{
if (doAll)
{
if (!filename.endsWith(QDir::separator()))
filename += "/";
}
QFileInfo fileInfo(filename);
QString path = fileInfo.absolutePath();
m_Settings->SaveFolder(path);//Any time they exit the box with a valid value, preserve it in the settings.
Path(filename);
m_Settings->SaveFolder(s);//Any time they exit the box with a valid value, preserve it in the settings.
Path(m_Controller->ComposePath(m_Controller->Name()));//And update the GUI.
SetMemory();
}
}
@ -452,17 +513,41 @@ void FractoriumFinalRenderDialog::OnFileButtonClicked(bool checked)
/// <param name="checked">Ignored</param>
void FractoriumFinalRenderDialog::OnShowFolderButtonClicked(bool checked)
{
QString text = Path();
QString s = m_Settings->SaveFolder();
if (text != "")
{
QFileInfo fileInfo(text);
QString path = fileInfo.absolutePath();
QDir dir(path);
if (Exists(s))
QDesktopServices::openUrl(QUrl::fromLocalFile(s));
else
QDesktopServices::openUrl(QStandardPaths::standardLocations(QStandardPaths::DesktopLocation)[0]);
}
if (dir.exists())
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
}
/// <summary>
/// Change the extension of the output image, which also may change the
/// number of channels used in the final output buffer.
/// </summary>
/// <param name="d">Ignored</param>
void FractoriumFinalRenderDialog::OnFinalRenderExtIndexChanged(int d)
{
if (SetMemory())
Path(m_Controller->ComposePath(m_Controller->Name()));
}
/// <summary>
/// Change the prefix prepended to the output file name.
/// </summary>
/// <param name="s">Ignored</param>
void FractoriumFinalRenderDialog::OnFinalRenderPrefixChanged(const QString& s)
{
Path(m_Controller->ComposePath(m_Controller->Name()));
}
/// <summary>
/// Change the suffix appended to the output file name.
/// </summary>
/// <param name="s">Ignored</param>
void FractoriumFinalRenderDialog::OnFinalRenderSuffixChanged(const QString& s)
{
Path(m_Controller->ComposePath(m_Controller->Name()));
}
/// <summary>
@ -492,27 +577,41 @@ void FractoriumFinalRenderDialog::OnCancelRenderClicked(bool checked)
/// <param name="e">The event</param>
void FractoriumFinalRenderDialog::showEvent(QShowEvent* e)
{
#ifdef DO_DOUBLE
Ember<double> ed;
#else
Ember<float> ed;
#endif
if (CreateControllerFromGUI(true))
{
m_Fractorium->m_Controller->CopyEmber(ed);//Copy the current ember from the main window out in to a temp.
m_Controller->SetEmber(ed);//Copy the temp into the final render controller.
m_Controller->SetOriginalEmber(ed);
#ifdef DO_DOUBLE
Ember<double> ed;
EmberFile<double> efi;
m_Fractorium->m_Controller->CopyEmberFile(efi, [&](Ember<double>& ember)
{
ember.SyncSize();
ember.m_Quality = m_Settings->FinalQuality();
ember.m_Supersample = m_Settings->FinalSupersample();
});//Copy the whole file, will take about 0.2ms per ember in the file.
#else
Ember<float> ed;
EmberFile<float> efi;
m_Fractorium->m_Controller->CopyEmberFile(efi, [&](Ember<float>& ember)
{
ember.SyncSize();
ember.m_Quality = m_Settings->FinalQuality();
ember.m_Supersample = m_Settings->FinalSupersample();
ember.m_TemporalSamples = m_Settings->FinalTemporalSamples();
});//Copy the whole file, will take about 0.2ms per ember in the file.
#endif
m_Controller->SetEmberFile(efi);//Copy the temp file into the final render controller.
m_Controller->SetEmber(m_Fractorium->m_Controller->Index());//Set the currently selected ember to the one that was being edited.
ui.FinalRenderCurrentSpin->setMaximum(efi.Size());
m_Controller->m_ImageCount = 0;
SetMemory();
m_Controller->ResetProgress();
QString s = m_Settings->SaveFolder();
if (Exists(s))
Path(m_Controller->ComposePath(m_Controller->Name()));//Update the GUI.
}
QDir dir(m_Settings->SaveFolder());
QString name = m_Controller->Name();
if (dir.exists() && name != "")
Path(dir.absolutePath() + "/" + name + ".png");
ui.FinalRenderTextOutput->clear();
QDialog::showEvent(e);
}
@ -542,23 +641,28 @@ bool FractoriumFinalRenderDialog::CreateControllerFromGUI(bool createRenderer)
bool ok = true;
#ifdef DO_DOUBLE
size_t size = Double() ? sizeof(double) : sizeof(float);
Ember<double> ed;
Ember<double> orig;
EmberFile<double> efd;
#else
size_t size = sizeof(float);
Ember<float> ed;
Ember<float> orig;
EmberFile<float> efd;
#endif
if (!m_Controller.get() || (m_Controller->SizeOfT() != size))
{
#ifdef DO_DOUBLE
size_t size = Double() ? sizeof(double) : sizeof(float);
Ember<double> ed;
Ember<double> orig;
EmberFile<double> efd;
#else
size_t size = sizeof(float);
Ember<float> ed;
Ember<float> orig;
EmberFile<float> efd;
#endif
//First check if a controller has already been created, and if so, save its embers and gracefully shut it down.
if (m_Controller.get())
{
m_Controller->CopyEmber(ed);//Convert float to double or save double verbatim;
m_Controller->CopyEmberFile(efd);
{
m_Controller->CopyEmberFile(efd);//Convert float to double or save double verbatim;
m_Controller->Shutdown();
}
@ -572,12 +676,7 @@ bool FractoriumFinalRenderDialog::CreateControllerFromGUI(bool createRenderer)
//Restore the ember and ember file.
if (m_Controller.get())
{
m_Controller->SetEmber(ed);//Convert float to double or set double verbatim;
m_Controller->SetEmberFile(efd);
m_Fractorium->m_Controller->CopyEmber(orig);//Copy the current ember from the main window out in to a temp.
m_Controller->SetOriginalEmber(orig);
}
m_Controller->SetEmberFile(efd);//Convert float to double or set double verbatim;
}
if (m_Controller.get())
@ -595,8 +694,13 @@ bool FractoriumFinalRenderDialog::CreateControllerFromGUI(bool createRenderer)
/// Compute the amount of memory needed via call to SyncAndComputeMemory(), then
/// assign the result to the table cell as text.
/// </summary>
void FractoriumFinalRenderDialog::SetMemory()
bool FractoriumFinalRenderDialog::SetMemory()
{
if (isVisible() && CreateControllerFromGUI(true))
ui.FinalRenderGeometryTable->item(5, 1)->setText(QLocale(QLocale::English).toString(m_Controller->SyncAndComputeMemory()));
{
ui.FinalRenderParamsTable->item(m_MemoryCellIndex, 1)->setText(ToString(m_Controller->SyncAndComputeMemory()));
return true;
}
return false;
}

View File

@ -3,7 +3,7 @@
#include "ui_FinalRenderDialog.h"
#include "SpinBox.h"
#include "DoubleSpinBox.h"
#include "TwoButtonWidget.h"
#include "TwoButtonComboWidget.h"
#include "FractoriumSettings.h"
#include "FinalRenderEmberController.h"
@ -53,21 +53,24 @@ public:
bool DoAll();
bool DoSequence();
bool KeepAspect();
bool ApplyToAll();
eScaleType Scale();
void Scale(eScaleType scale);
QString DoAllExt();
QString Ext();
QString Path();
void Path(QString s);
void Path(const QString& s);
QString Prefix();
QString Suffix();
unsigned int Current();
unsigned int PlatformIndex();
unsigned int DeviceIndex();
unsigned int ThreadCount();
unsigned int Width();
unsigned int Height();
double WidthScale();
double HeightScale();
double Quality();
unsigned int TemporalSamples();
unsigned int Supersample();
unsigned int Strips();
FinalRenderGuiState State();
public Q_SLOTS:
@ -77,17 +80,24 @@ public Q_SLOTS:
void OnTransparencyCheckBoxStateChanged(int state);
void OnOpenCLCheckBoxStateChanged(int state);
void OnDoublePrecisionCheckBoxStateChanged(int state);
void OnPlatformComboCurrentIndexChanged(int index);
void OnDoAllCheckBoxStateChanged(int state);
void OnDoSequenceCheckBoxStateChanged(int state);
void OnFinalRenderCurrentSpinChanged(int d);
void OnPlatformComboCurrentIndexChanged(int index);
void OnApplyAllCheckBoxStateChanged(int state);
void OnFinalRenderWidthScaleChanged(double d);
void OnFinalRenderHeightScaleChanged(double d);
void OnKeepAspectCheckBoxStateChanged(int state);
void OnScaleRadioButtonChanged(bool checked);
void OnWidthChanged(int d);
void OnHeightChanged(int d);
void OnQualityChanged(double d);
void OnTemporalSamplesChanged(int d);
void OnSupersampleChanged(int d);
void OnStripsChanged(int d);
void OnFileButtonClicked(bool checked);
void OnShowFolderButtonClicked(bool checked);
void OnFinalRenderExtIndexChanged(int d);
void OnFinalRenderPrefixChanged(const QString& s);
void OnFinalRenderSuffixChanged(const QString& s);
void OnRenderClicked(bool checked);
void OnCancelRenderClicked(bool checked);
@ -97,15 +107,19 @@ protected:
private:
bool CreateControllerFromGUI(bool createRenderer);
void SetMemory();
bool SetMemory();
int m_MemoryCellIndex;
int m_PathCellIndex;
OpenCLWrapper m_Wrapper;
Timing m_RenderTimer;
SpinBox* m_WidthSpin;
SpinBox* m_HeightSpin;
DoubleSpinBox* m_WidthScaleSpin;
DoubleSpinBox* m_HeightScaleSpin;
DoubleSpinBox* m_QualitySpin;
SpinBox* m_TemporalSamplesSpin;
SpinBox* m_SupersampleSpin;
SpinBox* m_StripsSpin;
TwoButtonComboWidget* m_Tbcw;
QLineEdit* m_PrefixEdit;
QLineEdit* m_SuffixEdit;
FractoriumSettings* m_Settings;

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>519</width>
<height>813</height>
<height>862</height>
</rect>
</property>
<property name="sizePolicy">
@ -64,7 +64,7 @@
<x>0</x>
<y>0</y>
<width>507</width>
<height>801</height>
<height>850</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
@ -85,137 +85,6 @@
</property>
<item>
<layout class="QGridLayout" name="gridLayout" columnstretch="0,0">
<item row="5" column="0">
<widget class="QGroupBox" name="FinalRenderScaleGroupBox">
<property name="minimumSize">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>40</height>
</size>
</property>
<property name="toolTip">
<string>The scaling to perform from the editor to the final rendered image</string>
</property>
<property name="title">
<string>Scale</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>4</number>
</property>
<property name="rightMargin">
<number>4</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item>
<widget class="QRadioButton" name="FinalRenderScaleNoneRadioButton">
<property name="text">
<string>None</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="FinalRenderScaleWidthRadioButton">
<property name="text">
<string>Width</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="FinalRenderScaleHeightRadioButton">
<property name="text">
<string>Height</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="5" column="1">
<widget class="QGroupBox" name="FinalRenderExtensionGroupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>110</width>
<height>40</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>40</height>
</size>
</property>
<property name="toolTip">
<string>The image type to save the final output as when rendering all open flames</string>
</property>
<property name="title">
<string>Render All Extension</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>4</number>
</property>
<property name="rightMargin">
<number>4</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item>
<widget class="QRadioButton" name="FinalRenderJpgRadioButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Jpg</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="FinalRenderPngRadioButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Png</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="FinalRenderEarlyClipCheckBox">
<property name="toolTip">
@ -226,49 +95,6 @@
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="FinalRenderSaveXmlCheckBox">
<property name="toolTip">
<string>Save an Xml parameter file for each flame rendered</string>
</property>
<property name="text">
<string>Save Xml</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="FinalRenderKeepAspectCheckBox">
<property name="toolTip">
<string>Maintain the aspect ratio between width and height to be equal to base width and base height</string>
</property>
<property name="text">
<string>Keep Aspect Ratio</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="FinalRenderDoSequenceCheckBox">
<property name="toolTip">
<string>Use temporal samples value to achieve motion blur effect between flames</string>
</property>
<property name="text">
<string>Render as Animation Sequence</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="FinalRenderDoAllCheckBox">
<property name="toolTip">
<string>Render all open flames instead of just the current one</string>
</property>
<property name="text">
<string>Render All</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="FinalRenderYAxisUpCheckBox">
<property name="toolTip">
@ -279,16 +105,6 @@
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="FinalRenderDoublePrecisionCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Checked: use 64-bit double precision numbers (slower, but better image quality).&lt;/p&gt;&lt;p&gt;Unchecked: use 32-bit single precision numbers (faster, but worse image quality).&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Use Double Precision</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="FinalRenderOpenCLCheckBox">
<property name="toolTip">
@ -309,50 +125,119 @@
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="FinalRenderDoublePrecisionCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Checked: use 64-bit double precision numbers (slower, but better image quality).&lt;/p&gt;&lt;p&gt;Unchecked: use 32-bit single precision numbers (faster, but worse image quality).&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Use Double Precision</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="FinalRenderSaveXmlCheckBox">
<property name="toolTip">
<string>Save an Xml parameter file for each flame rendered</string>
</property>
<property name="text">
<string>Save Xml</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="FinalRenderDoAllCheckBox">
<property name="toolTip">
<string>Render all open flames instead of just the current one</string>
</property>
<property name="text">
<string>Render All</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="FinalRenderDoSequenceCheckBox">
<property name="toolTip">
<string>Use temporal samples value to achieve motion blur effect between flames</string>
</property>
<property name="text">
<string>Render as Animation Sequence</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="FinalRenderPreviewLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<layout class="QGridLayout" name="gridLayout_3">
<property name="sizeConstraint">
<enum>QLayout::SetNoConstraint</enum>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>100</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>100</width>
<height>100</height>
</size>
</property>
<property name="sizeIncrement">
<size>
<width>1</width>
<height>1</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="text">
<string/>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
<item row="0" column="0">
<widget class="QLabel" name="FinalRenderPreviewLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>100</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>100</width>
<height>100</height>
</size>
</property>
<property name="sizeIncrement">
<size>
<width>1</width>
<height>1</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="text">
<string/>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="FinalRenderCurrentSpin">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="prefix">
<string/>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>999999999</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QComboBox" name="FinalRenderPlatformCombo">
@ -421,7 +306,256 @@
</widget>
</item>
<item>
<widget class="TableWidget" name="FinalRenderGeometryTable">
<widget class="QCheckBox" name="FinalRenderApplyToAllCheckBox">
<property name="toolTip">
<string>Apply current operation to all flames</string>
</property>
<property name="text">
<string>Apply Parameters to All</string>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="FinalRenderSizeGroupBox">
<property name="minimumSize">
<size>
<width>0</width>
<height>91</height>
</size>
</property>
<property name="title">
<string>Size</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>4</number>
</property>
<property name="horizontalSpacing">
<number>6</number>
</property>
<property name="verticalSpacing">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QTableWidget" name="FinalRenderSizeTable">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>44</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>44</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="frameShape">
<enum>QFrame::Panel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="tabKeyNavigation">
<bool>false</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="showGrid">
<bool>true</bool>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
<property name="rowCount">
<number>2</number>
</property>
<property name="columnCount">
<number>2</number>
</property>
<attribute name="horizontalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderDefaultSectionSize">
<number>85</number>
</attribute>
<attribute name="horizontalHeaderHighlightSections">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderMinimumSectionSize">
<number>35</number>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>22</number>
</attribute>
<attribute name="verticalHeaderHighlightSections">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderMinimumSectionSize">
<number>22</number>
</attribute>
<row>
<property name="text">
<string>Width Scale</string>
</property>
</row>
<row>
<property name="text">
<string>Height Scale</string>
</property>
</row>
<column>
<property name="text">
<string>Field</string>
</property>
</column>
<column/>
<item row="0" column="0">
<property name="text">
<string>Width Scale</string>
</property>
</item>
<item row="0" column="1">
<property name="text">
<string/>
</property>
</item>
<item row="1" column="0">
<property name="text">
<string>Height Scale</string>
</property>
</item>
<item row="1" column="1">
<property name="text">
<string/>
</property>
</item>
</widget>
</item>
<item row="0" column="1">
<widget class="QGroupBox" name="FinalRenderScaleGroupBox">
<property name="minimumSize">
<size>
<width>0</width>
<height>45</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>45</height>
</size>
</property>
<property name="toolTip">
<string>The scaling to perform from the editor to the final rendered image</string>
</property>
<property name="title">
<string>Scale Type</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<property name="leftMargin">
<number>4</number>
</property>
<property name="topMargin">
<number>4</number>
</property>
<property name="rightMargin">
<number>4</number>
</property>
<property name="bottomMargin">
<number>4</number>
</property>
<property name="spacing">
<number>4</number>
</property>
<item row="0" column="1">
<widget class="QRadioButton" name="FinalRenderScaleWidthRadioButton">
<property name="text">
<string>Width</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QRadioButton" name="FinalRenderScaleHeightRadioButton">
<property name="text">
<string>Height</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QRadioButton" name="FinalRenderScaleNoneRadioButton">
<property name="text">
<string>None</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="FinalRenderKeepAspectCheckBox">
<property name="toolTip">
<string>Maintain the aspect ratio between width and height to be equal to base width and base height</string>
</property>
<property name="text">
<string>Keep Aspect Ratio</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="TableWidget" name="FinalRenderParamsTable">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -431,13 +565,13 @@
<property name="minimumSize">
<size>
<width>0</width>
<height>200</height>
<height>178</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>200</height>
<height>178</height>
</size>
</property>
<property name="focusPolicy">
@ -521,19 +655,6 @@
<attribute name="verticalHeaderStretchLastSection">
<bool>false</bool>
</attribute>
<row>
<property name="text">
<string>Width</string>
</property>
<property name="toolTip">
<string/>
</property>
</row>
<row>
<property name="text">
<string>Height</string>
</property>
</row>
<row>
<property name="text">
<string>Quality</string>
@ -549,6 +670,11 @@
<string>Supersample</string>
</property>
</row>
<row>
<property name="text">
<string>Strips</string>
</property>
</row>
<row>
<property name="text">
<string>Memory Usage</string>
@ -581,10 +707,10 @@
</column>
<item row="0" column="0">
<property name="text">
<string>Width</string>
<string>Quality</string>
</property>
<property name="toolTip">
<string>The width in pixels of the final output image</string>
<string>The quality in iterations per pixel of the final output image</string>
</property>
</item>
<item row="0" column="1">
@ -594,10 +720,10 @@
</item>
<item row="1" column="0">
<property name="text">
<string>Height</string>
<string>Temporal Samples</string>
</property>
<property name="toolTip">
<string>The height in pixels of the final output image</string>
<string>The number of interpolated renders to do for each flame when rendering as an animation sequence</string>
</property>
</item>
<item row="1" column="1">
@ -607,10 +733,10 @@
</item>
<item row="2" column="0">
<property name="text">
<string>Quality</string>
<string>Supersample</string>
</property>
<property name="toolTip">
<string>The quality in iterations per pixel of the final output image</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The number to multiply the dimensions of the histogram and density filtering buffer by to achieve anti-aliasing.&lt;/p&gt;&lt;p&gt;Use this very sparingly as it increases the required memory by n squared.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</item>
<item row="2" column="1">
@ -620,10 +746,7 @@
</item>
<item row="3" column="0">
<property name="text">
<string>Temporal Samples</string>
</property>
<property name="toolTip">
<string>The number of interpolated renders to do for each flame when rendering as an animation sequence</string>
<string>Strips</string>
</property>
</item>
<item row="3" column="1">
@ -633,10 +756,10 @@
</item>
<item row="4" column="0">
<property name="text">
<string>Supersample</string>
<string>Memory Usage</string>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The number to multiply the dimensions of the histogram and density filtering buffer by to achieve anti-aliasing.&lt;/p&gt;&lt;p&gt;Use this very sparingly as it increases the required memory by n squared.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>The amount of memory including the final output image required to perform this render</string>
</property>
</item>
<item row="4" column="1">
@ -645,19 +768,6 @@
</property>
</item>
<item row="5" column="0">
<property name="text">
<string>Memory Usage</string>
</property>
<property name="toolTip">
<string>The amount of memory including the final output image required to perform this render</string>
</property>
</item>
<item row="5" column="1">
<property name="text">
<string>0</string>
</property>
</item>
<item row="6" column="0">
<property name="text">
<string>Output</string>
</property>
@ -665,25 +775,25 @@
<string>The output file path for rendering a single flame, or folder location for rendering multiple flames</string>
</property>
</item>
<item row="5" column="1">
<property name="text">
<string/>
</property>
</item>
<item row="6" column="0">
<property name="text">
<string>Prefix</string>
</property>
<property name="toolTip">
<string>The prefix to attach to all image filenames</string>
</property>
</item>
<item row="6" column="1">
<property name="text">
<string/>
</property>
</item>
<item row="7" column="0">
<property name="text">
<string>Prefix</string>
</property>
<property name="toolTip">
<string>The prefix to attach to all image filenames</string>
</property>
</item>
<item row="7" column="1">
<property name="text">
<string/>
</property>
</item>
<item row="8" column="0">
<property name="text">
<string>Suffix</string>
</property>
@ -691,7 +801,7 @@
<string>The suffix to attach to all image filenames</string>
</property>
</item>
<item row="8" column="1">
<item row="7" column="1">
<property name="text">
<string/>
</property>
@ -933,20 +1043,10 @@
<tabstop>FinalRenderYAxisUpCheckBox</tabstop>
<tabstop>FinalRenderTransparencyCheckBox</tabstop>
<tabstop>FinalRenderOpenCLCheckBox</tabstop>
<tabstop>FinalRenderDoublePrecisionCheckBox</tabstop>
<tabstop>FinalRenderSaveXmlCheckBox</tabstop>
<tabstop>FinalRenderDoAllCheckBox</tabstop>
<tabstop>FinalRenderDoSequenceCheckBox</tabstop>
<tabstop>FinalRenderKeepAspectCheckBox</tabstop>
<tabstop>FinalRenderScaleNoneRadioButton</tabstop>
<tabstop>FinalRenderScaleWidthRadioButton</tabstop>
<tabstop>FinalRenderScaleHeightRadioButton</tabstop>
<tabstop>FinalRenderJpgRadioButton</tabstop>
<tabstop>FinalRenderPngRadioButton</tabstop>
<tabstop>FinalRenderPlatformCombo</tabstop>
<tabstop>FinalRenderDeviceCombo</tabstop>
<tabstop>FinalRenderThreadCountSpin</tabstop>
<tabstop>FinalRenderGeometryTable</tabstop>
<tabstop>FinalRenderParamsTable</tabstop>
<tabstop>FinalRenderTextOutput</tabstop>
<tabstop>StartRenderButton</tabstop>
<tabstop>StopRenderButton</tabstop>

View File

@ -9,14 +9,14 @@
/// It passes a pointer to the main window to the base and initializes members.
/// </summary>
/// <param name="finalRender">Pointer to the final render dialog</param>
FinalRenderEmberControllerBase::FinalRenderEmberControllerBase(FractoriumFinalRenderDialog* finalRender)
: FractoriumEmberControllerBase(finalRender->m_Fractorium)
FinalRenderEmberControllerBase::FinalRenderEmberControllerBase(FractoriumFinalRenderDialog* finalRenderDialog)
: FractoriumEmberControllerBase(finalRenderDialog->m_Fractorium)
{
m_Run = false;
m_PreviewRun = false;
m_ImageCount = 0;
m_FinishedImageCount = 0;
m_FinalRender = finalRender;
m_FinalRenderDialog = finalRenderDialog;
m_Settings = m_Fractorium->m_Settings;
}
@ -55,7 +55,7 @@ void FinalRenderEmberControllerBase::CancelRender()
while (m_Result.isRunning())
QApplication::processEvents();
m_FinalRender->ui.FinalRenderTextOutput->append("Render canceled.");
m_FinalRenderDialog->ui.FinalRenderTextOutput->append("Render canceled.");
}
}
@ -66,14 +66,23 @@ void FinalRenderEmberControllerBase::CancelRender()
/// <returns>True if a valid renderer is created or if no action is taken, else false.</returns>
bool FinalRenderEmberControllerBase::CreateRendererFromGUI()
{
bool useOpenCL = m_Wrapper.CheckOpenCL() && m_FinalRender->OpenCL();
bool useOpenCL = m_Wrapper.CheckOpenCL() && m_FinalRenderDialog->OpenCL();
return CreateRenderer(useOpenCL ? OPENCL_RENDERER : CPU_RENDERER,
m_FinalRender->PlatformIndex(),
m_FinalRender->DeviceIndex(),
m_FinalRenderDialog->PlatformIndex(),
m_FinalRenderDialog->DeviceIndex(),
false);//Not shared.
}
/// <summary>
/// Thin wrapper around invoking a call to append text to the output.
/// </summary>
/// <param name="s">The string to append</param>
void FinalRenderEmberControllerBase::Output(const QString& s)
{
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderTextOutput, "append", Qt::QueuedConnection, Q_ARG(const QString&, s));
}
/// <summary>
/// Constructor which accepts a pointer to the final render dialog and passes it to the base.
/// The main final rendering lambda function is constructed here.
@ -86,7 +95,6 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
m_FinalPreviewRenderer = auto_ptr<EmberNs::Renderer<T, T>>(new EmberNs::Renderer<T, T>());
m_FinalPreviewRenderer->Callback(NULL);
m_FinalPreviewRenderer->NumChannels(4);
m_FinalPreviewRenderer->ReclaimOnResize(true);
m_FinalPreviewRenderFunc = [&]()
{
@ -94,38 +102,43 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
m_PreviewRun = true;
m_FinalPreviewRenderer->Abort();
QLabel* widget = m_FinalRender->ui.FinalRenderPreviewLabel;
unsigned int maxDim = 100u;
QLabel* widget = m_FinalRenderDialog->ui.FinalRenderPreviewLabel;
size_t maxDim = 100;
T scalePercentage;
//Determine how to scale the scaled ember to fit in the label with a max of 100x100.
if (m_Ember.m_FinalRasW >= m_Ember.m_FinalRasH)
scalePercentage = T(maxDim) / m_Ember.m_FinalRasW;
if (m_Ember->m_FinalRasW >= m_Ember->m_FinalRasH)
scalePercentage = T(maxDim) / m_Ember->m_FinalRasW;
else
scalePercentage = T(maxDim) / m_Ember.m_FinalRasH;
scalePercentage = T(maxDim) / m_Ember->m_FinalRasH;
m_PreviewEmber = m_Ember;
m_PreviewEmber = *m_Ember;
m_PreviewEmber.m_Quality = 100;
m_PreviewEmber.m_TemporalSamples = 1;
m_PreviewEmber.m_FinalRasW = min(maxDim, unsigned int(scalePercentage * m_Ember.m_FinalRasW));
m_PreviewEmber.m_FinalRasH = min(maxDim, unsigned int(scalePercentage * m_Ember.m_FinalRasH));
m_PreviewEmber.m_PixelsPerUnit = scalePercentage * m_Ember.m_PixelsPerUnit;
m_PreviewEmber.m_FinalRasW = max<size_t>(1, min<size_t>(maxDim, size_t(scalePercentage * m_Ember->m_FinalRasW)));//Ensure neither is zero.
m_PreviewEmber.m_FinalRasH = max<size_t>(1, min<size_t>(maxDim, size_t(scalePercentage * m_Ember->m_FinalRasH)));
m_PreviewEmber.m_PixelsPerUnit = scalePercentage * m_Ember->m_PixelsPerUnit;
while (!m_FinalPreviewRenderer->Aborted() || m_FinalPreviewRenderer->InRender())
QApplication::processEvents();
m_FinalPreviewRenderer->EarlyClip(m_FinalRender->EarlyClip());
m_FinalPreviewRenderer->YAxisUp(m_FinalRender->YAxisUp());
m_FinalPreviewRenderer->Transparency(m_FinalRender->Transparency());
m_FinalPreviewRenderer->EarlyClip(m_FinalRenderDialog->EarlyClip());
m_FinalPreviewRenderer->YAxisUp(m_FinalRenderDialog->YAxisUp());
m_FinalPreviewRenderer->Transparency(m_FinalRenderDialog->Transparency());
m_FinalPreviewRenderer->SetEmber(m_PreviewEmber);
m_FinalPreviewRenderer->PrepFinalAccumVector(m_PreviewFinalImage);//Must manually call this first because it could be erroneously made smaller due to strips if called inside Renderer::Run().
if (m_FinalPreviewRenderer->Run(m_PreviewFinalImage) == RENDER_OK)
{
QImage image(m_PreviewEmber.m_FinalRasW, m_PreviewEmber.m_FinalRasH, QImage::Format_RGBA8888);//The label wants RGBA.
memcpy(image.scanLine(0), m_PreviewFinalImage.data(), m_PreviewFinalImage.size() * sizeof(m_PreviewFinalImage[0]));//Memcpy the data in.
QPixmap pixmap = QPixmap::fromImage(image);
QMetaObject::invokeMethod(widget, "setPixmap", Qt::QueuedConnection, Q_ARG(QPixmap, pixmap));
}
unsigned int strips = VerifyStrips(m_PreviewEmber.m_FinalRasH, m_FinalRenderDialog->Strips(),
[&](const string& s) { }, [&](const string& s) { }, [&](const string& s) { });
StripsRender<T>(m_FinalPreviewRenderer.get(), m_PreviewEmber, m_PreviewFinalImage, 0, strips, m_FinalRenderDialog->YAxisUp(),
[&](size_t strip) { },//Pre strip.
[&](size_t strip) { },//Post strip.
[&](size_t strip) { },//Error.
[&](Ember<T>& finalEmber)//Final strip.
{
QImage image(finalEmber.m_FinalRasW, finalEmber.m_FinalRasH, QImage::Format_RGBA8888);//The label wants RGBA.
memcpy(image.scanLine(0), m_PreviewFinalImage.data(), finalEmber.m_FinalRasW * finalEmber.m_FinalRasH * 4);//Memcpy the data in.
QPixmap pixmap = QPixmap::fromImage(image);
QMetaObject::invokeMethod(widget, "setPixmap", Qt::QueuedConnection, Q_ARG(QPixmap, pixmap));
});
m_PreviewRun = false;
m_PreviewCs.Leave();
@ -136,50 +149,53 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
//If it finishes successfully, delete the backup file.
m_FinalRenderFunc = [&]()
{
size_t i;
m_Run = true;
m_TotalTimer.Tic();//Begin timing for progress.
m_GuiState = m_FinalRender->State();//Cache render settings from the GUI before running.
m_FinishedImageCount = 0;
QFileInfo original(m_GuiState.m_Path);
QString backup = original.absolutePath() + QDir::separator() + m_GuiState.m_Prefix + original.completeBaseName() + m_GuiState.m_Suffix + "_backup.flame";
QMetaObject::invokeMethod(m_Fractorium, "OnActionSaveCurrentToOpenedFile", Qt::QueuedConnection, Q_ARG(bool, true));//First, save the current ember back to its opened file.
m_Fractorium->m_Controller->CopyEmber(m_Ember);
m_Fractorium->m_Controller->CopyEmberFile(m_EmberFile);//Copy the whole file, will take about 0.2ms per ember in the file.
m_TotalTimer.Tic();//Begin timing for progress of all operations.
size_t i;
m_GuiState = m_FinalRenderDialog->State();//Cache render settings from the GUI before running.
bool doAll = m_GuiState.m_DoAll && m_EmberFile.Size() > 1;
unsigned int 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 backup = path + "_backup.flame";
//Save backup Xml.
if (m_GuiState.m_DoAll && m_EmberFile.m_Embers.size() > 1)
if (doAll)
m_XmlWriter.Save(backup.toStdString().c_str(), m_EmberFile.m_Embers, 0, true, false, true);
else
m_XmlWriter.Save(backup.toStdString().c_str(), m_Ember, 0, true, false, true);
m_XmlWriter.Save(backup.toStdString().c_str(), *m_Ember, 0, true, false, true);
QMetaObject::invokeMethod(m_FinalRender->ui.FinalRenderTextOutput, "setText", Qt::QueuedConnection, Q_ARG(QString, "Begin rendering..."));
m_FinishedImageCount = 0;
m_Renderer->EarlyClip(m_GuiState.m_EarlyClip);
m_Renderer->YAxisUp(m_GuiState.m_YAxisUp);
m_Renderer->ThreadCount(m_GuiState.m_ThreadCount);
m_Renderer->Transparency(m_GuiState.m_Transparency);
m_Renderer->m_ProgressParameter = (void*)&currentStripForProgress;
if (m_GuiState.m_Path.endsWith(".png", Qt::CaseInsensitive) || m_Renderer->RendererType() == OPENCL_RENDERER)
if (path.endsWith(".png", Qt::CaseInsensitive) || m_Renderer->RendererType() == OPENCL_RENDERER)//This is creating the wrong thing.//TODO
m_Renderer->NumChannels(4);
else
m_Renderer->NumChannels(3);
m_GuiState.m_Strips = VerifyStrips(m_Ember->m_FinalRasH, m_GuiState.m_Strips,
[&](const string& s) { Output(QString::fromStdString(s)); },//Greater than height.
[&](const string& s) { Output(QString::fromStdString(s)); },//Mod height != 0.
[&](const string& s) { Output(QString::fromStdString(s) + "\n"); });//Final strips value to be set.
//The rendering process is different between doing a single image, and doing multiple.
if (m_GuiState.m_DoAll && m_EmberFile.m_Embers.size() > 1)
if (doAll)
{
m_ImageCount = m_EmberFile.m_Embers.size();
m_ImageCount = m_EmberFile.Size();
ResetProgress();
//Different action required for rendering as animation or not.
if (m_GuiState.m_DoSequence)
{
Ember<T>* firstEmber = &m_EmberFile.m_Embers[0];
//Need to loop through and set all w, h, q, ts, ss and t vals.
for (i = 0; i < m_EmberFile.m_Embers.size() && m_Run; i++)
for (i = 0; i < m_EmberFile.Size() && m_Run; i++)
{
Sync(m_EmberFile.m_Embers[i]);
SyncGuiToEmber(m_EmberFile.m_Embers[i], firstEmber->m_FinalRasW, firstEmber->m_FinalRasH);
if (i > 0)
{
@ -194,184 +210,145 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
m_EmberFile.m_Embers[i].m_TemporalSamples = m_GuiState.m_TemporalSamples;
}
//Not supporting strips with motion blur.
//Shouldn't be a problem because animations will be at max 4k x 4k which will take about 1.1GB
//even when using double precision, which most cards at the time of this writing already exceed.
m_GuiState.m_Strips = 1;
m_Renderer->SetEmber(m_EmberFile.m_Embers);//Copy all embers to the local storage inside the renderer.
//Render each image, cancelling if m_Run ever gets set to false.
for (i = 0; i < m_EmberFile.m_Embers.size() && m_Run; i++)
for (i = 0; i < m_EmberFile.Size() && m_Run; i++)
{
Output("Image " + ToString(m_FinishedImageCount) + ":\n" + ComposePath(QString::fromStdString(m_EmberFile.m_Embers[i].m_Name)));
m_Renderer->Reset();//Have to manually set this since the ember is not set each time through.
m_RenderTimer.Tic();//Toc() is called in the progress function.
m_RenderTimer.Tic();//Toc() is called in RenderComplete().
if (m_Renderer->Run(m_FinalImage, i) != RENDER_OK)
StripsRender<T>(m_Renderer.get(), m_EmberFile.m_Embers[i], m_FinalImage, i, 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.
{
QMetaObject::invokeMethod(m_FinalRender->ui.FinalRenderTextOutput, "append", Qt::QueuedConnection, Q_ARG(QString, "Renderering failed.\n"));
m_Fractorium->ErrorReportToQTextEdit(m_Renderer->ErrorReport(), m_FinalRender->ui.FinalRenderTextOutput, false);
}
Output("Renderering failed.\n");
m_Fractorium->ErrorReportToQTextEdit(m_Renderer->ErrorReport(), m_FinalRenderDialog->ui.FinalRenderTextOutput, false);//Internally calls invoke.
},
[&](Ember<T>& finalEmber) { RenderComplete(finalEmber); });//Final strip.
}
}
else//Render all images, but not as an animation sequence (without temporal samples motion blur).
{
//Copy widget values to all embers
for (i = 0; i < m_EmberFile.m_Embers.size() && m_Run; i++)
for (i = 0; i < m_EmberFile.Size() && m_Run; i++)
{
Sync(m_EmberFile.m_Embers[i]);
m_EmberFile.m_Embers[i].m_TemporalSamples = 1;//No temporal sampling.
}
//Render each image, cancelling if m_Run ever gets set to false.
for (i = 0; i < m_EmberFile.m_Embers.size() && m_Run; i++)
for (i = 0; i < m_EmberFile.Size() && m_Run; i++)
{
Output("Image " + ToString(m_FinishedImageCount) + ":\n" + ComposePath(QString::fromStdString(m_EmberFile.m_Embers[i].m_Name)));
m_Renderer->SetEmber(m_EmberFile.m_Embers[i]);
m_RenderTimer.Tic();//Toc() is called in the progress function.
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().
if (m_Renderer->Run(m_FinalImage) != RENDER_OK)
StripsRender<T>(m_Renderer.get(), m_EmberFile.m_Embers[i], 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.
{
QMetaObject::invokeMethod(m_FinalRender->ui.FinalRenderTextOutput, "append", Qt::QueuedConnection, Q_ARG(QString, "Renderering failed.\n"));
m_Fractorium->ErrorReportToQTextEdit(m_Renderer->ErrorReport(), m_FinalRender->ui.FinalRenderTextOutput, false);
}
Output("Renderering failed.\n");
m_Fractorium->ErrorReportToQTextEdit(m_Renderer->ErrorReport(), m_FinalRenderDialog->ui.FinalRenderTextOutput, false);//Internally calls invoke.
},
[&](Ember<T>& finalEmber) { RenderComplete(finalEmber); });//Final strip.
}
}
}
else//Render a single image.
{
m_ImageCount = 1;
Sync(m_Ember);
ResetProgress();
m_Ember.m_TemporalSamples = 1;
m_Renderer->SetEmber(m_Ember);
memset(m_FinalImage.data(), 0, m_FinalImage.size() * sizeof(m_FinalImage[0]));
m_RenderTimer.Tic();//Toc() is called in the progress function.
if (m_Renderer->Run(m_FinalImage) != RENDER_OK)
m_Ember->m_TemporalSamples = 1;
m_Renderer->SetEmber(*m_Ember);
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);
Output(ComposePath(QString::fromStdString(m_Ember->m_Name)));
m_RenderTimer.Tic();//Toc() is called in RenderComplete().
StripsRender<T>(m_Renderer.get(), *m_Ember, 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.
{
QMetaObject::invokeMethod(m_FinalRender->ui.FinalRenderTextOutput, "append", Qt::QueuedConnection, Q_ARG(QString, "Renderering failed.\n"));
m_Fractorium->ErrorReportToQTextEdit(m_Renderer->ErrorReport(), m_FinalRender->ui.FinalRenderTextOutput, false);
}
Output("Renderering failed.\n");
m_Fractorium->ErrorReportToQTextEdit(m_Renderer->ErrorReport(), m_FinalRenderDialog->ui.FinalRenderTextOutput, false);//Internally calls invoke.
},
[&](Ember<T>& finalEmber) { RenderComplete(finalEmber); });//Final strip.
}
QString totalTimeString = "All renders completed in: " + QString::fromStdString(m_TotalTimer.Format(m_TotalTimer.Toc())) + ".";
Output(totalTimeString);
QFile::remove(backup);
m_Run = false;
};
}
/// <summary>
/// Virtual functions overridden from FractoriumEmberControllerBase.
/// </summary>
/// <summary>
/// Setters for embers and ember files which convert between float and double types.
/// These are used to preserve the current ember/file when switching between renderers.
/// Note that some precision will be lost when going from double to float.
/// </summary>
template <typename T> void FinalRenderEmberController<T>::SetEmber(const Ember<float>& ember, bool verbatim) { m_Ember = ember; }
template <typename T> void FinalRenderEmberController<T>::CopyEmber(Ember<float>& ember) { ember = m_Ember; }
template <typename T> void FinalRenderEmberController<T>::SetEmberFile(const EmberFile<float>& emberFile) { m_EmberFile = emberFile; }
template <typename T> void FinalRenderEmberController<T>::CopyEmberFile(EmberFile<float>& emberFile) { emberFile = m_EmberFile; }
template <typename T> void FinalRenderEmberController<T>::SetOriginalEmber(Ember<float>& ember) { m_OriginalEmber = ember; }
template <typename T> double FinalRenderEmberController<T>::OriginalAspect() { return double(m_OriginalEmber.m_OrigFinalRasW) / m_OriginalEmber.m_OrigFinalRasH; }
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]);
}
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);
}
#ifdef DO_DOUBLE
template <typename T> void FinalRenderEmberController<T>::SetEmber(const Ember<double>& ember, bool verbatim) { m_Ember = ember; }
template <typename T> void FinalRenderEmberController<T>::CopyEmber(Ember<double>& ember) { ember = m_Ember; }
template <typename T> void FinalRenderEmberController<T>::SetEmberFile(const EmberFile<double>& emberFile) { m_EmberFile = emberFile; }
template <typename T> void FinalRenderEmberController<T>::CopyEmberFile(EmberFile<double>& emberFile) { emberFile = m_EmberFile; }
template <typename T> void FinalRenderEmberController<T>::SetOriginalEmber(Ember<double>& ember) { m_OriginalEmber = ember; }
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]);
}
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);
}
#endif
/// <summary>
/// Progress function.
/// Take special action to sync options upon finishing.
/// Set the ember at the specified index from the currently opened file as the current Ember.
/// Clears the undo state.
/// Resets the rendering process.
/// </summary>
/// <param name="ember">The ember currently being rendered</param>
/// <param name="foo">An extra dummy parameter</param>
/// <param name="fraction">The progress fraction from 0-100</param>
/// <param name="stage">The stage of iteration. 1 is iterating, 2 is density filtering, 2 is final accumulation.</param>
/// <param name="etaMs">The estimated milliseconds to completion of the current stage</param>
/// <returns>0 if the user has clicked cancel, else 1 to continue rendering.</returns>
/// <param name="index">The index in the file from which to retrieve the ember</param>
template <typename T>
int FinalRenderEmberController<T>::ProgressFunc(Ember<T>& ember, void* foo, double fraction, int stage, double etaMs)
void FinalRenderEmberController<T>::SetEmber(size_t index)
{
static int count = 0;
int intFract = (int)fraction;
if (stage == 0)
QMetaObject::invokeMethod(m_FinalRender->ui.FinalRenderIterationProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, intFract));
else if (stage == 1)
QMetaObject::invokeMethod(m_FinalRender->ui.FinalRenderFilteringProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, intFract));
else if (stage == 2)
QMetaObject::invokeMethod(m_FinalRender->ui.FinalRenderAccumProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, intFract));
//Finished, so take special action.
if (stage == 2 && intFract == 100)
if (index < m_EmberFile.Size())
{
string renderTimeString = m_RenderTimer.Format(m_RenderTimer.Toc()), totalTimeString;
QString status, filename = m_GuiState.m_Path;
QFileInfo original(filename);
EmberStats stats = m_Renderer->Stats();
QString iters = QLocale(QLocale::English).toString(stats.m_Iters);
QString itersPerSec = QLocale(QLocale::English).toString(unsigned __int64(stats.m_Iters / (stats.m_IterMs / 1000.0)));
if (m_GuiState.m_DoAll && m_EmberFile.m_Embers.size() > 1)
filename = original.absolutePath() + QDir::separator() + m_GuiState.m_Prefix + QString::fromStdString(m_EmberFile.m_Embers[m_FinishedImageCount].m_Name) + m_GuiState.m_Suffix + "." + m_GuiState.m_DoAllExt;
else
filename = original.absolutePath() + QDir::separator() + m_GuiState.m_Prefix + original.completeBaseName() + m_GuiState.m_Suffix + "." + original.suffix();
filename = EmberFile<T>::UniqueFilename(filename);
//Save whatever options were specified on the GUI to the settings.
m_Settings->FinalEarlyClip(m_GuiState.m_EarlyClip);
m_Settings->FinalYAxisUp(m_GuiState.m_YAxisUp);
m_Settings->FinalTransparency(m_GuiState.m_Transparency);
m_Settings->FinalOpenCL(m_GuiState.m_OpenCL);
m_Settings->FinalDouble(m_GuiState.m_Double);
m_Settings->FinalPlatformIndex(m_GuiState.m_PlatformIndex);
m_Settings->FinalDeviceIndex(m_GuiState.m_DeviceIndex);
m_Settings->FinalSaveXml(m_GuiState.m_SaveXml);
m_Settings->FinalDoAll(m_GuiState.m_DoAll);
m_Settings->FinalDoSequence(m_GuiState.m_DoSequence);
m_Settings->FinalKeepAspect(m_GuiState.m_KeepAspect);
m_Settings->FinalScale(m_GuiState.m_Scale);
m_Settings->FinalDoAllExt(m_GuiState.m_DoAllExt);
m_Settings->FinalThreadCount(m_GuiState.m_ThreadCount);
m_Settings->FinalWidth(m_GuiState.m_Width);
m_Settings->FinalHeight(m_GuiState.m_Height);
m_Settings->FinalQuality(m_GuiState.m_Quality);
m_Settings->FinalTemporalSamples(m_GuiState.m_TemporalSamples);
m_Settings->FinalSupersample(m_GuiState.m_Supersample);
SaveCurrentRender(filename);
if (m_GuiState.m_SaveXml)
{
QFileInfo xmlFileInfo(filename);//Create another one in case it was modified for batch rendering.
QString newPath = xmlFileInfo.absolutePath() + QDir::separator() + xmlFileInfo.completeBaseName() + ".flame";
xmlDocPtr tempEdit = ember.m_Edits;
ember.m_Edits = m_XmlWriter.CreateNewEditdoc(&ember, NULL, "edit", m_Settings->Nick().toStdString(), m_Settings->Url().toStdString(), m_Settings->Id().toStdString(), "", 0, 0);
m_XmlWriter.Save(newPath.toStdString().c_str(), ember, 0, true, false, true);//Note that the ember passed is used, rather than m_Ember because it's what was actually rendered.
if (tempEdit != NULL)
xmlFreeDoc(tempEdit);
}
m_FinishedImageCount++;
QMetaObject::invokeMethod(m_FinalRender->ui.FinalRenderIterationProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, 100));//Just to be safe.
QMetaObject::invokeMethod(m_FinalRender->ui.FinalRenderFilteringProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, 100));
QMetaObject::invokeMethod(m_FinalRender->ui.FinalRenderAccumProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, 100));
QMetaObject::invokeMethod(m_FinalRender->ui.FinalRenderTotalProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, int(((float)m_FinishedImageCount / (float)m_ImageCount) * 100)));
QMetaObject::invokeMethod(m_FinalRender->ui.FinalRenderImageCountLabel, "setText", Qt::QueuedConnection, Q_ARG(QString, QString::number(m_FinishedImageCount) + " / " + QString::number(m_ImageCount)));
status = "Image " + QString::number(m_FinishedImageCount) + ":\nPure render time: " + QString::fromStdString(renderTimeString);
QMetaObject::invokeMethod(m_FinalRender->ui.FinalRenderTextOutput, "append", Qt::QueuedConnection, Q_ARG(QString, status));
totalTimeString = m_TotalTimer.Format(m_TotalTimer.Toc());
status = "Total render time: " + QString::fromStdString(totalTimeString) + "\nTotal iters: " + iters + "\nIters/second: " + itersPerSec + "\n";
QMetaObject::invokeMethod(m_FinalRender->ui.FinalRenderTextOutput, "append", Qt::QueuedConnection, Q_ARG(QString, status));
QMetaObject::invokeMethod(m_FinalRender, "MoveCursorToEnd", Qt::QueuedConnection);
if (m_FinishedImageCount != m_ImageCount)
{
ResetProgress(false);
}
m_Ember = &(m_EmberFile.m_Embers[index]);
SyncCurrentToGui();
}
else
{
m_Ember = &(m_EmberFile.m_Embers[0]);//Should never happen.
}
QMetaObject::invokeMethod(m_FinalRender->ui.FinalRenderTextOutput, "update", Qt::QueuedConnection);
QApplication::processEvents();
return m_Run ? 1 : 0;
}
/// <summary>
@ -382,17 +359,17 @@ int FinalRenderEmberController<T>::ProgressFunc(Ember<T>& ember, void* foo, doub
template<typename T>
bool FinalRenderEmberController<T>::Render()
{
QString filename = m_FinalRender->Path();
QString filename = m_FinalRenderDialog->Path();
if (filename == "")
{
QMessageBox::critical(m_FinalRender, "File Error", "Please enter a valid path and filename for the output.");
m_Fractorium->ShowCritical("File Error", "Please enter a valid path and filename for the output.");
return false;
}
if (CreateRendererFromGUI())
{
m_FinalRender->ui.FinalRenderTextOutput->clear();
m_FinalRenderDialog->ui.FinalRenderTextOutput->setText("Preparing all parameters.\n");
//Note that a Qt thread must be used, rather than a tbb task.
//This is because tbb does a very poor job of allocating thread resources
@ -422,8 +399,7 @@ bool FinalRenderEmberController<T>::CreateRenderer(eRendererType renderType, uns
{
bool ok = true;
vector<string> errorReport;
QString filename = m_FinalRender->Path();
unsigned int channels = filename.endsWith(".png", Qt::CaseInsensitive) ? 4 : 3;
unsigned int channels = m_FinalRenderDialog->Ext() == "png" ? 4 : 3;
CancelRender();
@ -441,14 +417,14 @@ bool FinalRenderEmberController<T>::CreateRenderer(eRendererType renderType, uns
m_Device = device;
m_OutputTexID = 0;//Don't care about tex ID when doing final render.
m_Shared = shared;
m_Renderer = auto_ptr<EmberNs::RendererBase>(::CreateRenderer<T, T>(renderType, platform, device, shared, m_OutputTexID, emberReport));
errorReport = emberReport.ErrorReport();
if (!errorReport.empty())
{
ok = false;
QMessageBox::critical(m_Fractorium, "Renderer Creation Error", "Could not create requested renderer, fallback CPU renderer created. See info tab for details.");
m_Fractorium->ShowCritical("Renderer Creation Error", "Could not create requested renderer, fallback CPU renderer created. See info tab for details.");
m_Fractorium->ErrorReportToQTextEdit(errorReport, m_Fractorium->ui.InfoRenderingTextEdit);
}
}
@ -460,50 +436,109 @@ bool FinalRenderEmberController<T>::CreateRenderer(eRendererType renderType, uns
m_Renderer->Callback(this);
m_Renderer->NumChannels(channels);
m_Renderer->ReclaimOnResize(true);
m_Renderer->EarlyClip(m_FinalRender->EarlyClip());
m_Renderer->YAxisUp(m_FinalRender->YAxisUp());
m_Renderer->ThreadCount(m_FinalRender->ThreadCount());
m_Renderer->Transparency(m_FinalRender->Transparency());
m_Renderer->EarlyClip(m_FinalRenderDialog->EarlyClip());
m_Renderer->YAxisUp(m_FinalRenderDialog->YAxisUp());
m_Renderer->ThreadCount(m_FinalRenderDialog->ThreadCount());
m_Renderer->Transparency(m_FinalRenderDialog->Transparency());
}
else
{
ok = false;
QMessageBox::critical(m_FinalRender, "Renderer Creation Error", "Could not create renderer, aborting. See info tab for details.");
m_Fractorium->ShowCritical("Renderer Creation Error", "Could not create renderer, aborting. See info tab for details.");
}
return ok;
}
/// <summary>
/// Set various parameters in the renderer and current ember with the values
/// specified in the widgets and compute the amount of memory required to render.
/// This includes the memory needed for the final output image.
/// Progress function.
/// Take special action to sync options upon finishing.
/// </summary>
/// <returns>If successful, memory required in bytes, else zero.</returns>
/// <param name="ember">The ember currently being rendered</param>
/// <param name="foo">An extra dummy parameter</param>
/// <param name="fraction">The progress fraction from 0-100</param>
/// <param name="stage">The stage of iteration. 1 is iterating, 2 is density filtering, 2 is final accumulation.</param>
/// <param name="etaMs">The estimated milliseconds to completion of the current stage</param>
/// <returns>0 if the user has clicked cancel, else 1 to continue rendering.</returns>
template <typename T>
unsigned __int64 FinalRenderEmberController<T>::SyncAndComputeMemory()
int FinalRenderEmberController<T>::ProgressFunc(Ember<T>& ember, void* foo, double fraction, int stage, double etaMs)
{
if (m_Renderer.get())
{
bool b = false;
QString filename = m_FinalRender->Path();
unsigned int channels = filename.endsWith(".png", Qt::CaseInsensitive) ? 4 : 3;//4 channels for Png, else 3.
static int count = 0;
unsigned int strip = *((unsigned int*)m_Renderer->m_ProgressParameter);
double fracPerStrip = ceil(100.0 / m_GuiState.m_Strips);
double stripsfrac = ceil(fracPerStrip * strip) + ceil(fraction / m_GuiState.m_Strips);
int intFract = (int)stripsfrac;
Sync(m_Ember);
m_Renderer->SetEmber(m_Ember);
m_Renderer->CreateSpatialFilter(b);
m_Renderer->CreateTemporalFilter(b);
m_Renderer->NumChannels(channels);
m_Renderer->ComputeBounds();
CancelPreviewRender();
//m_FinalPreviewResult = QtConcurrent::run(m_PreviewRenderFunc);
//while (!m_FinalPreviewResult.isRunning()) { QApplication::processEvents(); }//Wait for it to start up.
m_FinalPreviewRenderFunc();
return m_Renderer->MemoryRequired(true);
if (stage == 0)
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderIterationProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, intFract));
else if (stage == 1)
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderFilteringProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, intFract));
else if (stage == 2)
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderAccumProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, intFract));
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderTextOutput, "update", Qt::QueuedConnection);
//QApplication::processEvents();
return m_Run ? 1 : 0;
}
/// <summary>
/// Virtual functions overridden from FinalRenderEmberControllerBase.
/// </summary>
/// <summary>
/// Copy current ember values to widgets.
/// </summary>
template <typename T>
void FinalRenderEmberController<T>::SyncCurrentToGui()
{
SyncCurrentToSizeSpinners(true, true);
m_FinalRenderDialog->ui.FinalRenderCurrentSpin->setSuffix(" " + Name());
m_FinalRenderDialog->Scale(m_Ember->ScaleType());
m_FinalRenderDialog->m_QualitySpin->SetValueStealth(m_Ember->m_Quality);
m_FinalRenderDialog->m_SupersampleSpin->SetValueStealth(m_Ember->m_Supersample);
m_FinalRenderDialog->Path(ComposePath(EmberFile<T>::UniqueFilename(Name())));
}
/// <summary>
/// Copy GUI values to either the current ember, or all embers in the file
/// depending on whether Render All is checked.
/// </summary>
/// <param name="widthOverride">Width override to use instead of scaling the original width</param>
/// <param name="heightOverride">Height override to use instead of scaling the original height</param>
template <typename T>
void FinalRenderEmberController<T>::SyncGuiToEmbers(size_t widthOverride, size_t heightOverride)
{
if (m_FinalRenderDialog->ApplyToAll())
{
for (size_t i = 0; i < m_EmberFile.Size(); i++)
SyncGuiToEmber(m_EmberFile.m_Embers[i], widthOverride, heightOverride);
}
else
{
SyncGuiToEmber(*m_Ember, widthOverride, heightOverride);
}
}
/// <summary>
/// Set values for scale spinners based on the ratio of the original dimensions to the current dimensions
/// of the current ember. Also update the size suffix text.
/// </summary>
/// <param name="scale">Whether to update the scale values</param>
/// <param name="size">Whether to update the size suffix text</param>
template <typename T>
void FinalRenderEmberController<T>::SyncCurrentToSizeSpinners(bool scale, bool size)
{
if (scale)
{
m_FinalRenderDialog->m_WidthScaleSpin->SetValueStealth((double)m_Ember->m_FinalRasW / m_Ember->m_OrigFinalRasW);//Work backward to determine the scale.
m_FinalRenderDialog->m_HeightScaleSpin->SetValueStealth((double)m_Ember->m_FinalRasH / m_Ember->m_OrigFinalRasH);
}
return 0;
if (size)
{
m_FinalRenderDialog->m_WidthScaleSpin->setSuffix(" (" + ToString(m_Ember->m_FinalRasW) + ")");
m_FinalRenderDialog->m_HeightScaleSpin->setSuffix(" (" + ToString(m_Ember->m_FinalRasH) + ")");
}
}
/// <summary>
@ -515,15 +550,67 @@ void FinalRenderEmberController<T>::ResetProgress(bool total)
{
if (total)
{
QMetaObject::invokeMethod(m_FinalRender->ui.FinalRenderImageCountLabel, "setText", Qt::QueuedConnection, Q_ARG(QString, "0 / " + QString::number(m_ImageCount)));
QMetaObject::invokeMethod(m_FinalRender->ui.FinalRenderTotalProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, 0));
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderImageCountLabel, "setText", Qt::QueuedConnection, Q_ARG(const QString&, "0 / " + ToString(m_ImageCount)));
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderTotalProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, 0));
}
QMetaObject::invokeMethod(m_FinalRender->ui.FinalRenderIterationProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, 0));
QMetaObject::invokeMethod(m_FinalRender->ui.FinalRenderFilteringProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, 0));
QMetaObject::invokeMethod(m_FinalRender->ui.FinalRenderAccumProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, 0));
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderIterationProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, 0));
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderFilteringProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, 0));
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderAccumProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, 0));
}
/// <summary>
/// Set various parameters in the renderer and current ember with the values
/// specified in the widgets and compute the amount of memory required to render.
/// This includes the memory needed for the final output image.
/// </summary>
/// <returns>If successful, memory required in bytes, else zero.</returns>
template <typename T>
size_t FinalRenderEmberController<T>::SyncAndComputeMemory()
{
if (m_Renderer.get())
{
bool b = false;
unsigned int channels = m_FinalRenderDialog->Ext() == "png" ? 4 : 3;//4 channels for Png, else 3.
SyncGuiToEmbers();
m_Renderer->SetEmber(*m_Ember);
m_Renderer->CreateSpatialFilter(b);
m_Renderer->CreateTemporalFilter(b);
m_Renderer->NumChannels(channels);
m_Renderer->ComputeBounds();
CancelPreviewRender();
m_FinalPreviewRenderFunc();
return m_Renderer->MemoryRequired(m_FinalRenderDialog->Strips(), true);
}
return 0;
}
/// <summary>
/// Compose a final output path given a base name.
/// This includes the base path, the prefix, the name, the suffix and the
/// extension.
/// </summary>
/// <param name="name">The base filename to compose a full path for</param>
/// <returns>The fully composed path</returns>
template <typename T>
QString FinalRenderEmberController<T>::ComposePath(const QString& name)
{
QString path = MakeEnd(m_Settings->SaveFolder(), '/');//Base path.
QString full = path + m_FinalRenderDialog->Prefix() + name + m_FinalRenderDialog->Suffix() + "." + m_FinalRenderDialog->Ext();
return full;
}
/// <summary>
/// Non-virtual functions declared in FinalRenderEmberController<T>.
/// </summary>
/// <summary>
/// Stop the preview renderer.
/// This is meant to only be called programatically and never by the user.
/// </summary>
template <typename T>
void FinalRenderEmberController<T>::CancelPreviewRender()
{
@ -534,23 +621,105 @@ void FinalRenderEmberController<T>::CancelPreviewRender()
while (m_FinalPreviewResult.isRunning()) { QApplication::processEvents(); }
}
/// <summary>
/// Action to take when rendering an image completes.
/// </summary>
/// <param name="ember">The ember currently being rendered</param>
template<typename T>
void FinalRenderEmberController<T>::RenderComplete(Ember<T>& ember)
{
string renderTimeString = m_RenderTimer.Format(m_RenderTimer.Toc()), totalTimeString;
QString status, filename = ComposePath(EmberFile<T>::UniqueFilename(QString::fromStdString(ember.m_Name)));
QString itersString = ToString(m_Stats.m_Iters);
QString itersPerSecString = ToString(size_t(m_Stats.m_Iters / (m_Stats.m_IterMs / 1000.0)));
//Save whatever options were specified on the GUI to the settings.
m_Settings->FinalEarlyClip(m_GuiState.m_EarlyClip);
m_Settings->FinalYAxisUp(m_GuiState.m_YAxisUp);
m_Settings->FinalTransparency(m_GuiState.m_Transparency);
m_Settings->FinalOpenCL(m_GuiState.m_OpenCL);
m_Settings->FinalDouble(m_GuiState.m_Double);
m_Settings->FinalPlatformIndex(m_GuiState.m_PlatformIndex);
m_Settings->FinalDeviceIndex(m_GuiState.m_DeviceIndex);
m_Settings->FinalSaveXml(m_GuiState.m_SaveXml);
m_Settings->FinalDoAll(m_GuiState.m_DoAll);
m_Settings->FinalDoSequence(m_GuiState.m_DoSequence);
m_Settings->FinalKeepAspect(m_GuiState.m_KeepAspect);
m_Settings->FinalScale(m_GuiState.m_Scale);
m_Settings->FinalExt(m_GuiState.m_Ext);
m_Settings->FinalThreadCount(m_GuiState.m_ThreadCount);
m_Settings->FinalQuality(m_GuiState.m_Quality);
m_Settings->FinalTemporalSamples(m_GuiState.m_TemporalSamples);
m_Settings->FinalSupersample(m_GuiState.m_Supersample);
m_Settings->FinalStrips(m_GuiState.m_Strips);
SaveCurrentRender(filename, false);//Don't pull from the card, the rendering process already did it.
if (m_GuiState.m_SaveXml)
{
QFileInfo xmlFileInfo(filename);//Create another one in case it was modified for batch rendering.
QString newPath = xmlFileInfo.absolutePath() + '/' + xmlFileInfo.completeBaseName() + ".flame";
xmlDocPtr tempEdit = ember.m_Edits;
ember.m_Edits = m_XmlWriter.CreateNewEditdoc(&ember, NULL, "edit", m_Settings->Nick().toStdString(), m_Settings->Url().toStdString(), m_Settings->Id().toStdString(), "", 0, 0);
m_XmlWriter.Save(newPath.toStdString().c_str(), ember, 0, true, false, true);//Note that the ember passed is used, rather than m_Ember because it's what was actually rendered.
if (tempEdit != NULL)
xmlFreeDoc(tempEdit);
}
m_FinishedImageCount++;
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderIterationProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, 100));//Just to be safe.
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderFilteringProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, 100));
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderAccumProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, 100));
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderTotalProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, int(((float)m_FinishedImageCount / (float)m_ImageCount) * 100)));
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderImageCountLabel, "setText", Qt::QueuedConnection, Q_ARG(const QString&, ToString(m_FinishedImageCount) + " / " + ToString(m_ImageCount)));
status = "Pure render time: " + QString::fromStdString(renderTimeString);
Output(status);
totalTimeString = m_RenderTimer.Format(m_RenderTimer.Toc());
status = "Total time: " + QString::fromStdString(totalTimeString) + "\nTotal iters: " + itersString + "\nIters/second: " + itersPerSecString + "\n";
Output(status);
QMetaObject::invokeMethod(m_FinalRenderDialog, "MoveCursorToEnd", Qt::QueuedConnection);
if (m_FinishedImageCount != m_ImageCount)
{
ResetProgress(false);
}
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderTextOutput, "update", Qt::QueuedConnection);
}
/// <summary>
/// Copy widget values to the ember passed in.
/// </summary>
/// <param name="ember">The ember whose values will be modified</param>
/// <param name="widthOverride">Width override to use instead of scaling the original width</param>
/// <param name="heightOverride">Height override to use instead of scaling the original height</param>
template <typename T>
void FinalRenderEmberController<T>::Sync(Ember<T>& ember)
void FinalRenderEmberController<T>::SyncGuiToEmber(Ember<T>& ember, size_t widthOverride, size_t heightOverride)
{
int w = m_FinalRender->m_WidthSpin->value();
int h = m_FinalRender->m_HeightSpin->value();
size_t w;
size_t h;
ember.m_FinalRasW = m_OriginalEmber.m_OrigFinalRasW;//Scale is always in terms of the original dimensions of the ember in the editor.
ember.m_FinalRasH = m_OriginalEmber.m_OrigFinalRasH;
ember.m_PixelsPerUnit = m_OriginalEmber.m_PixelsPerUnit;
ember.SetSizeAndAdjustScale(w, h, false, m_FinalRender->Scale());
ember.m_Quality = m_FinalRender->m_QualitySpin->value();
ember.m_Supersample = m_FinalRender->m_SupersampleSpin->value();
if (widthOverride && heightOverride)
{
w = widthOverride;
h = heightOverride;
}
else
{
double wScale = m_FinalRenderDialog->m_WidthScaleSpin->value();
double hScale = m_FinalRenderDialog->m_HeightScaleSpin->value();
if (m_FinalRender->ui.FinalRenderDoSequenceCheckBox->isChecked())
ember.m_TemporalSamples = m_FinalRender->m_TemporalSamplesSpin->value();
w = ember.m_OrigFinalRasW * wScale;
h = ember.m_OrigFinalRasH * hScale;
}
w = max<size_t>(w, 10);
h = max<size_t>(h, 10);
ember.SetSizeAndAdjustScale(w, h, false, m_FinalRenderDialog->Scale());
ember.m_Quality = m_FinalRenderDialog->m_QualitySpin->value();
ember.m_Supersample = m_FinalRenderDialog->m_SupersampleSpin->value();
}

View File

@ -31,17 +31,18 @@ struct FinalRenderGuiState
bool m_KeepAspect;
eScaleType m_Scale;
QString m_Path;
QString m_DoAllExt;
QString m_Ext;
QString m_Prefix;
QString m_Suffix;
unsigned int m_PlatformIndex;
unsigned int m_DeviceIndex;
unsigned int m_ThreadCount;
unsigned int m_Width;
unsigned int m_Height;
double m_WidthScale;
double m_HeightScale;
double m_Quality;
unsigned int m_TemporalSamples;
unsigned int m_Supersample;
unsigned int m_Strips;
};
/// <summary>
@ -55,20 +56,20 @@ class FinalRenderEmberControllerBase : public FractoriumEmberControllerBase
friend FractoriumFinalRenderDialog;
public:
FinalRenderEmberControllerBase(FractoriumFinalRenderDialog* finalRender);
FinalRenderEmberControllerBase(FractoriumFinalRenderDialog* finalRenderDialog);
virtual ~FinalRenderEmberControllerBase() { }
virtual unsigned __int64 SyncAndComputeMemory() { return 0; }
virtual QString Name() const { return ""; }
virtual void SyncCurrentToGui() { }
virtual void SyncGuiToEmbers(size_t widthOverride = 0, size_t heightOverride = 0) { }
virtual void SyncCurrentToSizeSpinners(bool scale, bool size) { }
virtual void ResetProgress(bool total = true) { }
virtual void SetOriginalEmber(Ember<float>& ember) { }
#ifdef DO_DOUBLE
virtual void SetOriginalEmber(Ember<double>& ember) { }
#endif
virtual size_t SyncAndComputeMemory() { return 0; }
virtual double OriginalAspect() { return 1; }
virtual QString ComposePath(const QString& name) { return ""; }
void CancelRender();
bool CreateRendererFromGUI();
void Output(const QString& s);
protected:
bool m_Run;
@ -82,7 +83,7 @@ protected:
std::function<void (void)> m_FinalPreviewRenderFunc;
FractoriumSettings* m_Settings;
FractoriumFinalRenderDialog* m_FinalRender;
FractoriumFinalRenderDialog* m_FinalRenderDialog;
FinalRenderGuiState m_GuiState;
OpenCLWrapper m_Wrapper;
CriticalSection m_PreviewCs;
@ -101,33 +102,36 @@ public:
FinalRenderEmberController(FractoriumFinalRenderDialog* finalRender);
virtual ~FinalRenderEmberController() { }
virtual void SetEmber(const Ember<float>& ember, bool verbatim = false);
virtual void CopyEmber(Ember<float>& ember);
virtual void SetEmberFile(const EmberFile<float>& emberFile);
virtual void CopyEmberFile(EmberFile<float>& emberFile);
virtual void SetOriginalEmber(Ember<float>& ember);
//Virtual functions overridden from FractoriumEmberControllerBase.
virtual void SetEmberFile(const EmberFile<float>& emberFile) override;
virtual void CopyEmberFile(EmberFile<float>& emberFile, std::function<void(Ember<float>& ember)> perEmberOperation = [&](Ember<float>& ember) { }) override;
#ifdef DO_DOUBLE
virtual void SetEmber(const Ember<double>& ember, bool verbatim = false);
virtual void CopyEmber(Ember<double>& ember);
virtual void SetEmberFile(const EmberFile<double>& emberFile);
virtual void CopyEmberFile(EmberFile<double>& emberFile);
virtual void SetOriginalEmber(Ember<double>& ember);
virtual void SetEmberFile(const EmberFile<double>& emberFile) override;
virtual void CopyEmberFile(EmberFile<double>& emberFile, std::function<void(Ember<double>& ember)> perEmberOperation = [&](Ember<double>& ember) { }) override;
#endif
virtual double OriginalAspect();
virtual int ProgressFunc(Ember<T>& ember, void* foo, double fraction, int stage, double etaMs);
virtual bool Render();
virtual bool CreateRenderer(eRendererType renderType, unsigned int platform, unsigned int device, bool shared = true);
virtual unsigned int SizeOfT() { return sizeof(T); }
virtual unsigned __int64 SyncAndComputeMemory();
virtual QString Name() const { return QString::fromStdString(m_Ember.m_Name); }
virtual void ResetProgress(bool total = true);
void CancelPreviewRender();
virtual void SetEmber(size_t index) override;
virtual bool Render() override;
virtual bool CreateRenderer(eRendererType renderType, unsigned int platform, unsigned int device, bool shared = true) override;
virtual int ProgressFunc(Ember<T>& ember, void* foo, double fraction, int stage, double etaMs) override;
virtual size_t Index() const override { return m_Ember->m_Index; }
virtual unsigned int SizeOfT() const override { return sizeof(T); }
//Virtual functions overridden from FinalRenderEmberControllerBase.
virtual void SyncCurrentToGui() override;
virtual void SyncGuiToEmbers(size_t widthOverride = 0, size_t heightOverride = 0) override;
virtual void SyncCurrentToSizeSpinners(bool scale, bool size) override;
virtual void ResetProgress(bool total = true) override;
virtual size_t SyncAndComputeMemory() override;
virtual double OriginalAspect() override { return double(m_Ember->m_OrigFinalRasW) / m_Ember->m_OrigFinalRasH; }
virtual QString Name() const override { return QString::fromStdString(m_Ember->m_Name); }
virtual QString ComposePath(const QString& name) override;
protected:
void Sync(Ember<T>& ember);
void CancelPreviewRender();
void RenderComplete(Ember<T>& ember);
void SyncGuiToEmber(Ember<T>& ember, size_t widthOverride = 0, size_t heightOverride = 0);
Ember<T> m_Ember;
Ember<T> m_OriginalEmber;
Ember<T>* m_Ember;
Ember<T> m_PreviewEmber;
EmberFile<T> m_EmberFile;
EmberToXml<T> m_XmlWriter;

View File

@ -165,18 +165,6 @@ Fractorium::~Fractorium()
m_Settings->sync();
}
/// <summary>
/// Stop the render timer and start the delayed restart timer.
/// This is a massive hack because Qt has no way of detecting when a resize event
/// is started and stopped. Detecting if mouse buttons down is also not an option
/// because the documentation says it gives the wrong result.
/// </summary>
void Fractorium::Resize()
{
if (!QCoreApplication::closingDown())
m_Controller->DelayedStartRenderTimer();
}
/// <summary>
/// Set the coordinate text in the status bar.
/// </summary>
@ -198,11 +186,9 @@ void Fractorium::SetCoordinateStatus(int x, int y, float worldX, float worldY)
template <typename T>
void FractoriumEmberController<T>::ApplyXmlSavingTemplate(Ember<T>& ember)
{
ember.m_FinalRasW = m_Fractorium->m_Settings->XmlWidth();
ember.m_FinalRasH = m_Fractorium->m_Settings->XmlHeight();
ember.m_TemporalSamples = m_Fractorium->m_Settings->XmlTemporalSamples();
ember.m_Quality = m_Fractorium->m_Settings->XmlQuality();
ember.m_Supersample = m_Fractorium->m_Settings->XmlSupersample();
ember.m_TemporalSamples = m_Fractorium->m_Settings->XmlTemporalSamples();
}
/// <summary>
@ -260,11 +246,13 @@ void Fractorium::dockLocationChanged(Qt::DockWidgetArea area)
/// </summary>
/// <summary>
/// Resize event, just pass to base.
/// Resize event, change width and height double click values to match the window size.
/// </summary>
/// <param name="e">The event</param>
void Fractorium::resizeEvent(QResizeEvent* e)
{
m_WidthSpin->DoubleClickNonZero(ui.GLParentScrollArea->width());
m_HeightSpin->DoubleClickNonZero(ui.GLParentScrollArea->height());
QMainWindow::resizeEvent(e);
}
@ -362,7 +350,7 @@ void Fractorium::dropEvent(QDropEvent* e)
void Fractorium::SetupCombo(QTableWidget* table, const QObject* receiver, int& row, int col, StealthComboBox*& comboBox, vector<string>& vals, const char* signal, const char* slot, Qt::ConnectionType connectionType)
{
comboBox = new StealthComboBox(table);
ForEach(vals, [&](string s) { comboBox->addItem(s.c_str()); });
ForEach(vals, [&](const string& s) { comboBox->addItem(s.c_str()); });
table->setCellWidget(row, col, comboBox);
connect(comboBox, signal, receiver, slot, connectionType);
row++;
@ -425,7 +413,7 @@ QStringList Fractorium::SetupOpenXmlDialog()
/// </summary>
/// <param name="defaultFilename">The default filename to populate the text box with</param>
/// <returns>The filename selected</returns>
QString Fractorium::SetupSaveXmlDialog(QString defaultFilename)
QString Fractorium::SetupSaveXmlDialog(const QString& defaultFilename)
{
//Lazy instantiate since it takes a long time.
if (!m_FileDialog)
@ -463,7 +451,7 @@ QString Fractorium::SetupSaveXmlDialog(QString defaultFilename)
/// </summary>
/// <param name="defaultFilename">The default filename to populate the text box with</param>
/// <returns>The filename selected</returns>
QString Fractorium::SetupSaveImageDialog(QString defaultFilename)
QString Fractorium::SetupSaveImageDialog(const QString& defaultFilename)
{
//Lazy instantiate since it takes a long time.
if (!m_FileDialog)
@ -502,7 +490,7 @@ QString Fractorium::SetupSaveImageDialog(QString defaultFilename)
/// Setup and show the save folder dialog.
/// This will perform lazy instantiation.
/// </summary>
/// <returns>The folder selected</returns>
/// <returns>The folder selected, with '/' appended to the end</returns>
QString Fractorium::SetupSaveFolderDialog()
{
//Lazy instantiate since it takes a long time.
@ -528,11 +516,28 @@ QString Fractorium::SetupSaveFolderDialog()
m_FolderDialog->setDirectory(m_Settings->SaveFolder());
if (m_FolderDialog->exec() == QDialog::Accepted)
filename = m_FolderDialog->selectedFiles().value(0);
{
filename = MakeEnd(m_FolderDialog->selectedFiles().value(0), '/');
}
return filename;
}
/// <summary>
/// Thin wrapper around QMessageBox::critical() to allow it to be invoked from another thread.
/// </summary>
void Fractorium::ShowCritical(const QString& title, const QString& text, bool invokeRequired)
{
if (!invokeRequired)
{
QMessageBox::critical(this, title, text);
}
else
{
QMetaObject::invokeMethod(this, "ShowCritical", Qt::QueuedConnection, Q_ARG(const QString&, title), Q_ARG(const QString&, text), Q_ARG(bool, false));
}
}
/// <summary>
/// Explicitly set the tab orders for the entire program.
/// Qt has a facility to do this, but it fails when using custom widgets in

View File

@ -71,7 +71,6 @@ public:
void SetCenter(float x, float y);
void SetRotation(double rot, bool stealth);
void SetScale(double scale);
void Resize();
void SetCoordinateStatus(int x, int y, float worldX, float worldY);
//Xforms.
@ -230,6 +229,7 @@ public slots:
void StartRenderTimer();
void IdleTimer();
bool ControllersOk();
void ShowCritical(const QString& title, const QString& text, bool invokeRequired = false);
//Can't have a template function be a slot.
void SetLibraryTreeItemData(EmberTreeWidgetItemBase* item, vector<unsigned char>& v, unsigned int width, unsigned int height);
@ -243,11 +243,11 @@ public:
static int FlipDet(Affine2D<float>& affine);
protected:
virtual void resizeEvent(QResizeEvent* e);
virtual void closeEvent(QCloseEvent* e);
virtual void dragEnterEvent(QDragEnterEvent* e);
virtual void dragMoveEvent(QDragMoveEvent* e);
virtual void dropEvent(QDropEvent* e);
virtual void resizeEvent(QResizeEvent* e) override;
virtual void closeEvent(QCloseEvent* e) override;
virtual void dragEnterEvent(QDragEnterEvent* e) override;
virtual void dragMoveEvent(QDragMoveEvent* e) override;
virtual void dropEvent(QDropEvent* e) override;
private:
void InitMenusUI();
@ -294,8 +294,8 @@ private:
//Dialogs.
QStringList SetupOpenXmlDialog();
QString SetupSaveXmlDialog(QString defaultFilename);
QString SetupSaveImageDialog(QString defaultFilename);
QString SetupSaveXmlDialog(const QString& defaultFilename);
QString SetupSaveImageDialog(const QString& defaultFilename);
QString SetupSaveFolderDialog();
QColorDialog* m_ColorDialog;
FractoriumFinalRenderDialog* m_FinalRenderDialog;
@ -461,5 +461,52 @@ static QWidget* SetTabOrder(QWidget* parent, QWidget* w1, QWidget* w2)
return w2;
}
/// <summary>
/// Wrapper around QLocale::system().toDouble().
/// </summary>
/// <param name="s">The string to convert</param>
/// <param name="ok">Pointer to boolean which stores the success value of the conversion</param>
/// <returns>The converted value if successful, else 0.</returns>
static double ToDouble(const QString &s, bool *ok)
{
return QLocale::system().toDouble(s, ok);
}
/// <summary>
/// Wrapper around QLocale::system().toString().
/// </summary>
/// <param name="s">The value to convert</param>
/// <returns>The string value if successful, else "".</returns>
template <typename T>
static QString ToString(T val)
{
return QLocale::system().toString(val);
}
/// <summary>
/// Force a QString to end with the specified value.
/// </summary>
/// <param name="s">The string to append a suffix to</param>
/// <param name="e">The suffix to append</param>
/// <returns>The original string value if it already ended in e, else the original value appended with e.</returns>
template <typename T>
static QString MakeEnd(const QString& s, T e)
{
if (!s.endsWith(e))
return s + e;
else
return s;
}
/// <summary>
/// Check if a path is not empty and exists on the file system.
/// </summary>
/// <param name="s">The path to check</param>
/// <returns>True if s was not empty and existed, else false.</returns>
static bool Exists(const QString& s)
{
return s != "" && QDir(s).exists();
}
//template void Fractorium::SetupSpinner<SpinBox, int> (QTableWidget* table, const QObject* receiver, int& row, int col, SpinBox*& spinBox, int height, int min, int max, int step, const char* signal, const char* slot, bool incRow, int val, int doubleClickZero, int doubleClickNonZero);
//template void Fractorium::SetupSpinner<DoubleSpinBox, double>(QTableWidget* table, const QObject* receiver, int& row, int col, DoubleSpinBox*& spinBox, int height, double min, double max, double step, const char* signal, const char* slot, bool incRow, double val, double doubleClickZero, double doubleClickNonZero);

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>1173</width>
<height>988</height>
<width>1214</width>
<height>983</height>
</rect>
</property>
<property name="sizePolicy">
@ -32,107 +32,143 @@
<property name="styleSheet">
<string notr="true"/>
</property>
<widget class="GLWidget" name="GLDisplay">
<property name="palette">
<palette>
<active>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>240</red>
<green>240</green>
<blue>240</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>240</red>
<green>240</green>
<blue>240</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>240</red>
<green>240</green>
<blue>240</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>240</red>
<green>240</green>
<blue>240</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
<widget class="QScrollArea" name="GLParentScrollArea">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="cursor">
<cursorShape>ArrowCursor</cursorShape>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="mouseTracking">
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="acceptDrops">
<bool>true</bool>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>6</number>
<widget class="QWidget" name="GLParentScrollAreaContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>930</width>
<height>942</height>
</rect>
</property>
<property name="topMargin">
<number>6</number>
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
</layout>
<widget class="GLWidget" name="GLDisplay" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>914</width>
<height>824</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="palette">
<palette>
<active>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>240</red>
<green>240</green>
<blue>240</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>240</red>
<green>240</green>
<blue>240</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>240</red>
<green>240</green>
<blue>240</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>240</red>
<green>240</green>
<blue>240</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="cursor">
<cursorShape>ArrowCursor</cursorShape>
</property>
<property name="mouseTracking">
<bool>true</bool>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="acceptDrops">
<bool>true</bool>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
</widget>
</widget>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1173</width>
<width>1214</width>
<height>21</height>
</rect>
</property>
@ -140,7 +176,7 @@
<property name="title">
<string>&amp;File</string>
</property>
<property name="toolTipsVisible" stdset="0">
<property name="toolTipsVisible">
<bool>true</bool>
</property>
<addaction name="ActionNewFlock"/>
@ -167,7 +203,7 @@
<property name="title">
<string>&amp;Tools</string>
</property>
<property name="toolTipsVisible" stdset="0">
<property name="toolTipsVisible">
<bool>true</bool>
</property>
<addaction name="ActionAddReflectiveSymmetry"/>
@ -189,7 +225,7 @@
<property name="title">
<string>&amp;Edit</string>
</property>
<property name="toolTipsVisible" stdset="0">
<property name="toolTipsVisible">
<bool>true</bool>
</property>
<addaction name="ActionUndo"/>
@ -382,7 +418,7 @@
<x>0</x>
<y>0</y>
<width>252</width>
<height>857</height>
<height>852</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_11">
@ -485,8 +521,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>252</width>
<height>857</height>
<width>98</width>
<height>847</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
@ -2781,8 +2817,8 @@ SpinBox
<rect>
<x>0</x>
<y>0</y>
<width>238</width>
<height>752</height>
<width>118</width>
<height>597</height>
</rect>
</property>
<property name="palette">
@ -4952,8 +4988,8 @@ SpinBox
<rect>
<x>0</x>
<y>0</y>
<width>256</width>
<height>861</height>
<width>105</width>
<height>684</height>
</rect>
</property>
<property name="sizePolicy">

View File

@ -65,7 +65,7 @@ FractoriumEmberControllerBase::~FractoriumEmberControllerBase()
/// <param name="fractorium">Pointer to the main window.</param>
template <typename T>
FractoriumEmberController<T>::FractoriumEmberController(Fractorium* fractorium)
: FractoriumEmberControllerBase(fractorium)
: FractoriumEmberControllerBase(fractorium)
{
m_PreviewRun = false;
m_PreviewRunning = false;
@ -79,7 +79,6 @@ FractoriumEmberController<T>::FractoriumEmberController(Fractorium* fractorium)
m_PreviewRenderer->Callback(NULL);
m_PreviewRenderer->NumChannels(4);
m_PreviewRenderer->ReclaimOnResize(true);
m_PreviewRenderer->EarlyClip(m_Fractorium->m_Settings->EarlyClip());
m_PreviewRenderer->YAxisUp(m_Fractorium->m_Settings->YAxisUp());
m_PreviewRenderer->SetEmber(m_Ember);//Give it an initial ember, will be updated many times later.
@ -98,7 +97,7 @@ FractoriumEmberController<T>::FractoriumEmberController(Fractorium* fractorium)
if (QTreeWidgetItem* top = tree->topLevelItem(0))
{
for (size_t i = start; m_PreviewRun && i < end && i < m_EmberFile.m_Embers.size(); i++)
for (size_t i = start; m_PreviewRun && i < end && i < m_EmberFile.Size(); i++)
{
Ember<T> ember = m_EmberFile.m_Embers[i];
@ -144,21 +143,38 @@ FractoriumEmberController<T>::~FractoriumEmberController() { }
/// Note that some precision will be lost when going from double to float.
/// </summary>
template <typename T> void FractoriumEmberController<T>::SetEmber(const Ember<float>& ember, bool verbatim) { SetEmberPrivate<float>(ember, verbatim); }
template <typename T> void FractoriumEmberController<T>::CopyEmber(Ember<float>& ember) { ember = m_Ember; }
template <typename T> void FractoriumEmberController<T>::CopyEmber(Ember<float>& ember, std::function<void(Ember<float>& ember)> perEmberOperation) { ember = m_Ember; perEmberOperation(ember); }
template <typename T> void FractoriumEmberController<T>::SetEmberFile(const EmberFile<float>& emberFile) { m_EmberFile = emberFile; }
template <typename T> void FractoriumEmberController<T>::CopyEmberFile(EmberFile<float>& emberFile) { emberFile = m_EmberFile; }
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);
}
template <typename T> void FractoriumEmberController<T>::SetTempPalette(const Palette<float>& palette) { m_TempPalette = palette; }
template <typename T> void FractoriumEmberController<T>::CopyTempPalette(Palette<float>& palette) { palette = m_TempPalette; }
#ifdef DO_DOUBLE
template <typename T> void FractoriumEmberController<T>::SetEmber(const Ember<double>& ember, bool verbatim) { SetEmberPrivate<double>(ember, verbatim); }
template <typename T> void FractoriumEmberController<T>::CopyEmber(Ember<double>& ember) { ember = m_Ember; }
template <typename T> void FractoriumEmberController<T>::CopyEmber(Ember<double>& ember, std::function<void(Ember<double>& ember)> perEmberOperation) { ember = m_Ember; perEmberOperation(ember); }
template <typename T> void FractoriumEmberController<T>::SetEmberFile(const EmberFile<double>& emberFile) { m_EmberFile = emberFile; }
template <typename T> void FractoriumEmberController<T>::CopyEmberFile(EmberFile<double>& emberFile) { emberFile = m_EmberFile; }
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);
}
template <typename T> void FractoriumEmberController<T>::SetTempPalette(const Palette<double>& palette) { m_TempPalette = palette; }
template <typename T> void FractoriumEmberController<T>::CopyTempPalette(Palette<double>& palette) { palette = m_TempPalette; }
#endif
template <typename T> Ember<T>* FractoriumEmberController<T>::CurrentEmber() { return &m_Ember; }
template <typename T>
void FractoriumEmberController<T>::ConstrainDimensions(Ember<T>& ember)
{
ember.m_FinalRasW = std::min<int>(m_Fractorium->ui.GLDisplay->MaxTexSize(), ember.m_FinalRasW);
ember.m_FinalRasH = std::min<int>(m_Fractorium->ui.GLDisplay->MaxTexSize(), ember.m_FinalRasH);
}
/// <summary>
/// Set the ember at the specified index from the currently opened file as the current Ember.
/// Clears the undo state.
@ -168,7 +184,7 @@ template <typename T> Ember<T>* FractoriumEmberController<T>::CurrentEmber() { r
template <typename T>
void FractoriumEmberController<T>::SetEmber(size_t index)
{
if (index < m_EmberFile.m_Embers.size())
if (index < m_EmberFile.Size())
{
if (QTreeWidgetItem* top = m_Fractorium->ui.LibraryTree->topLevelItem(0))
{
@ -235,7 +251,7 @@ void FractoriumEmberController<T>::SetEmberPrivate(const Ember<U>& ember, bool v
if (!verbatim)
{
m_Ember.SetSizeAndAdjustScale(m_Fractorium->ui.GLDisplay->width(), m_Fractorium->ui.GLDisplay->height(), true, SCALE_WIDTH);
//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

@ -41,16 +41,16 @@ public:
//Embers.
virtual void SetEmber(const Ember<float>& ember, bool verbatim = false) { }
virtual void CopyEmber(Ember<float>& ember) { }
virtual void CopyEmber(Ember<float>& ember, std::function<void(Ember<float>& ember)> perEmberOperation = [&](Ember<float>& ember) { }) { }
virtual void SetEmberFile(const EmberFile<float>& emberFile) { }
virtual void CopyEmberFile(EmberFile<float>& emberFile) { }
virtual void CopyEmberFile(EmberFile<float>& emberFile, std::function<void(Ember<float>& ember)> perEmberOperation = [&](Ember<float>& ember) { }) { }
virtual void SetTempPalette(const Palette<float>& palette) { }
virtual void CopyTempPalette(Palette<float>& palette) { }
#ifdef DO_DOUBLE
virtual void SetEmber(const Ember<double>& ember, bool verbatim = false) { }
virtual void CopyEmber(Ember<double>& ember) { }
virtual void CopyEmber(Ember<double>& ember, std::function<void(Ember<double>& ember)> perEmberOperation = [&](Ember<double>& ember) { }) { }
virtual void SetEmberFile(const EmberFile<double>& emberFile) { }
virtual void CopyEmberFile(EmberFile<double>& emberFile) { }
virtual void CopyEmberFile(EmberFile<double>& emberFile, std::function<void(Ember<double>& ember)> perEmberOperation = [&](Ember<double>& ember) { }) { }
virtual void SetTempPalette(const Palette<double>& palette) { }
virtual void CopyTempPalette(Palette<double>& palette) { }
#endif
@ -62,14 +62,15 @@ public:
virtual void DeleteCurrentXform() { }
virtual void AddFinalXform() { }
virtual bool UseFinalXform() { return false; }
virtual size_t XformCount() { return 0; }
virtual size_t TotalXformCount() { return 0; }
virtual string Name() { return ""; }
virtual void Name(string s) { }
virtual unsigned int FinalRasW() { return 0; }
virtual size_t XformCount() const { return 0; }
virtual size_t TotalXformCount() const { return 0; }
virtual QString Name() const { return ""; }
virtual void Name(const string& s) { }
virtual unsigned int FinalRasW() const { return 0; }
virtual void FinalRasW(unsigned int w) { }
virtual unsigned int FinalRasH() { return 0; }
virtual unsigned int FinalRasH() const { return 0; }
virtual void FinalRasH(unsigned int h) { }
virtual size_t Index() const { return 0; }
virtual void AddSymmetry(int sym, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) { }
virtual void CalcNormalizedWeights() { }
@ -78,7 +79,7 @@ public:
virtual void NewEmptyFlameInCurrentFile() { }
virtual void NewRandomFlameInCurrentFile() { }
virtual void CopyFlameInCurrentFile() { }
virtual void OpenAndPrepFiles(QStringList filenames, bool append) { }
virtual void OpenAndPrepFiles(const QStringList& filenames, bool append) { }
virtual void SaveCurrentAsXml() { }
virtual void SaveEntireFileAsXml() { }
virtual void SaveCurrentToOpenedFile() { }
@ -106,6 +107,8 @@ public:
virtual void VibrancyChanged(double d) { }
virtual void HighlightPowerChanged(double d) { }
virtual void PaletteModeChanged(unsigned int i) { }
virtual void WidthChanged(unsigned int i) { }
virtual void HeightChanged(unsigned int i) { }
virtual void CenterXChanged(double d) { }
virtual void CenterYChanged(double d) { }
virtual void ScaleChanged(double d) { }
@ -165,7 +168,7 @@ public:
virtual void ClearXaos() { }
//Palette.
virtual bool InitPaletteTable(string s) { return false; }
virtual bool InitPaletteTable(const string& s) { return false; }
virtual void ApplyPaletteToEmber() { }
virtual void PaletteAdjust() { }
virtual QRgb GetQRgbFromPaletteIndex(unsigned int i) { return QRgb(); }
@ -185,7 +188,7 @@ public:
//Rendering/progress.
virtual bool Render() { return false; }
virtual bool CreateRenderer(eRendererType renderType, unsigned int platform, unsigned int device, bool shared = true) { return false; }
virtual unsigned int SizeOfT() { return 0; }
virtual unsigned int SizeOfT() const { return 0; }
virtual void ClearUndo() { }
virtual GLEmberControllerBase* GLController() { return NULL; }
bool RenderTimerRunning();
@ -195,7 +198,7 @@ public:
void Shutdown();
void UpdateRender(eProcessAction action = FULL_RENDER);
void DeleteRenderer();
void SaveCurrentRender(QString filename);
void SaveCurrentRender(const QString& filename, bool forcePull);
RendererBase* Renderer() { return m_Renderer.get(); }
vector<unsigned char>* FinalImage() { return &m_FinalImage; }
vector<unsigned char>* PreviewFinalImage() { return &m_PreviewFinalImage; }
@ -219,6 +222,7 @@ protected:
eEditUndoState m_EditState;
GLuint m_OutputTexID;
Timing m_RenderElapsedTimer;
EmberStats m_Stats;
QImage m_FinalPaletteImage;
QString m_LastSaveAll;
QString m_LastSaveCurrent;
@ -247,161 +251,165 @@ public:
virtual ~FractoriumEmberController();
//Embers.
virtual void SetEmber(const Ember<float>& ember, bool verbatim = false);
virtual void CopyEmber(Ember<float>& ember);
virtual void SetEmberFile(const EmberFile<float>& emberFile);
virtual void CopyEmberFile(EmberFile<float>& emberFile);
virtual void SetTempPalette(const Palette<float>& palette);
virtual void CopyTempPalette(Palette<float>& palette);
virtual void SetEmber(const Ember<float>& ember, bool verbatim = false) override;
virtual void CopyEmber(Ember<float>& ember, std::function<void(Ember<float>& ember)> perEmberOperation = [&](Ember<float>& ember) { }) override;
virtual void SetEmberFile(const EmberFile<float>& emberFile) override;
virtual void CopyEmberFile(EmberFile<float>& emberFile, std::function<void(Ember<float>& ember)> perEmberOperation = [&](Ember<float>& ember) { }) override;
virtual void SetTempPalette(const Palette<float>& palette) override;
virtual void CopyTempPalette(Palette<float>& palette) override;
#ifdef DO_DOUBLE
virtual void SetEmber(const Ember<double>& ember, bool verbatim = false);
virtual void CopyEmber(Ember<double>& ember);
virtual void SetEmberFile(const EmberFile<double>& emberFile);
virtual void CopyEmberFile(EmberFile<double>& emberFile);
virtual void SetTempPalette(const Palette<double>& palette);
virtual void CopyTempPalette(Palette<double>& palette);
virtual void SetEmber(const Ember<double>& ember, bool verbatim = false) override;
virtual void CopyEmber(Ember<double>& ember, std::function<void(Ember<double>& ember)> perEmberOperation = [&](Ember<double>& ember) { }) override;
virtual void SetEmberFile(const EmberFile<double>& emberFile) override;
virtual void CopyEmberFile(EmberFile<double>& emberFile, std::function<void(Ember<double>& ember)> perEmberOperation = [&](Ember<double>& ember) { }) override;
virtual void SetTempPalette(const Palette<double>& palette) override;
virtual void CopyTempPalette(Palette<double>& palette) override;
#endif
virtual void SetEmber(size_t index);
virtual void Clear() { }
virtual void AddXform();
virtual void DuplicateXform();
virtual void ClearCurrentXform();
virtual void DeleteCurrentXform();
virtual void AddFinalXform();
virtual bool UseFinalXform() { return m_Ember.UseFinalXform(); }
virtual void SetEmber(size_t index) override;
virtual void Clear() override { }
virtual void AddXform() override;
virtual void DuplicateXform() override;
virtual void ClearCurrentXform() override;
virtual void DeleteCurrentXform() override;
virtual void AddFinalXform() override;
virtual bool UseFinalXform() override { return m_Ember.UseFinalXform(); }
//virtual bool IsFinal(unsigned int i) { return false; }
virtual size_t XformCount() { return m_Ember.XformCount(); }
virtual size_t TotalXformCount() { return m_Ember.TotalXformCount(); }
virtual string Name() { return m_Ember.m_Name; }
virtual void Name(string s) { m_Ember.m_Name = s; }
virtual unsigned int FinalRasW() { return m_Ember.m_FinalRasW; }
virtual void FinalRasW(unsigned int w) { m_Ember.m_FinalRasW = w; }
virtual unsigned int FinalRasH() { return m_Ember.m_FinalRasH; }
virtual void FinalRasH(unsigned int h) { m_Ember.m_FinalRasH = h; }
virtual void AddSymmetry(int sym, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) { m_Ember.AddSymmetry(sym, rand); }
virtual void CalcNormalizedWeights() { m_Ember.CalcNormalizedWeights(m_NormalizedWeights); }
virtual size_t XformCount() const override { return m_Ember.XformCount(); }
virtual size_t TotalXformCount() const override { return m_Ember.TotalXformCount(); }
virtual QString Name() const override { return QString::fromStdString(m_Ember.m_Name); }
virtual void Name(const string& s) override { m_Ember.m_Name = s; }
virtual unsigned int FinalRasW() const override { return m_Ember.m_FinalRasW; }
virtual void FinalRasW(unsigned int w) override { m_Ember.m_FinalRasW = w; }
virtual unsigned int FinalRasH() const override { return m_Ember.m_FinalRasH; }
virtual void FinalRasH(unsigned int h) override { m_Ember.m_FinalRasH = h; }
virtual size_t Index() const override { return m_Ember.m_Index; }
virtual void AddSymmetry(int sym, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override { m_Ember.AddSymmetry(sym, rand); }
virtual void CalcNormalizedWeights() override { m_Ember.CalcNormalizedWeights(m_NormalizedWeights); }
void ConstrainDimensions(Ember<T>& ember);
Ember<T>* CurrentEmber();
//Menu.
virtual void NewFlock(unsigned int count);
virtual void NewEmptyFlameInCurrentFile();
virtual void NewRandomFlameInCurrentFile();
virtual void CopyFlameInCurrentFile();
virtual void OpenAndPrepFiles(QStringList filenames, bool append);
virtual void SaveCurrentAsXml();
virtual void SaveEntireFileAsXml();
virtual void SaveCurrentToOpenedFile();
virtual void Undo();
virtual void Redo();
virtual void CopyXml();
virtual void CopyAllXml();
virtual void PasteXmlAppend();
virtual void PasteXmlOver();
virtual void AddReflectiveSymmetry();
virtual void AddRotationalSymmetry();
virtual void AddBothSymmetry();
virtual void Flatten();
virtual void Unflatten();
virtual void ClearFlame();
virtual void NewFlock(unsigned int count) override;
virtual void NewEmptyFlameInCurrentFile() override;
virtual void NewRandomFlameInCurrentFile() override;
virtual void CopyFlameInCurrentFile() override;
virtual void OpenAndPrepFiles(const QStringList& filenames, bool append) override;
virtual void SaveCurrentAsXml() override;
virtual void SaveEntireFileAsXml() override;
virtual void SaveCurrentToOpenedFile() override;
virtual void Undo() override;
virtual void Redo() override;
virtual void CopyXml() override;
virtual void CopyAllXml() override;
virtual void PasteXmlAppend() override;
virtual void PasteXmlOver() override;
virtual void AddReflectiveSymmetry() override;
virtual void AddRotationalSymmetry() override;
virtual void AddBothSymmetry() override;
virtual void Flatten() override;
virtual void Unflatten() override;
virtual void ClearFlame() override;
//Toolbar.
//Params.
virtual void SetCenter(double x, double y);
virtual void FillParamTablesAndPalette();
virtual void BrightnessChanged(double d);
virtual void GammaChanged(double d);
virtual void GammaThresholdChanged(double d);
virtual void VibrancyChanged(double d);
virtual void HighlightPowerChanged(double d);
virtual void PaletteModeChanged(unsigned int i);
virtual void CenterXChanged(double d);
virtual void CenterYChanged(double d);
virtual void ScaleChanged(double d);
virtual void ZoomChanged(double d);
virtual void RotateChanged(double d);
virtual void ZPosChanged(double d);
virtual void PerspectiveChanged(double d);
virtual void PitchChanged(double d);
virtual void YawChanged(double d);
virtual void DepthBlurChanged(double d);
virtual void SpatialFilterWidthChanged(double d);
virtual void SpatialFilterTypeChanged(const QString& text);
virtual void TemporalFilterWidthChanged(double d);
virtual void TemporalFilterTypeChanged(const QString& text);
virtual void DEFilterMinRadiusWidthChanged(double d);
virtual void DEFilterMaxRadiusWidthChanged(double d);
virtual void DEFilterCurveWidthChanged(double d);
virtual void PassesChanged(int d);
virtual void TemporalSamplesChanged(int d);
virtual void QualityChanged(double d);
virtual void SupersampleChanged(int d);
virtual void AffineInterpTypeChanged(int index);
virtual void InterpTypeChanged(int index);
virtual void BackgroundChanged(const QColor& col);
virtual void SetCenter(double x, double y) override;
virtual void FillParamTablesAndPalette() override;
virtual void BrightnessChanged(double d) override;
virtual void GammaChanged(double d) override;
virtual void GammaThresholdChanged(double d) override;
virtual void VibrancyChanged(double d) override;
virtual void HighlightPowerChanged(double d) override;
virtual void PaletteModeChanged(unsigned int i) override;
virtual void WidthChanged(unsigned int i) override;
virtual void HeightChanged(unsigned int i) override;
virtual void CenterXChanged(double d) override;
virtual void CenterYChanged(double d) override;
virtual void ScaleChanged(double d) override;
virtual void ZoomChanged(double d) override;
virtual void RotateChanged(double d) override;
virtual void ZPosChanged(double d) override;
virtual void PerspectiveChanged(double d) override;
virtual void PitchChanged(double d) override;
virtual void YawChanged(double d) override;
virtual void DepthBlurChanged(double d) override;
virtual void SpatialFilterWidthChanged(double d) override;
virtual void SpatialFilterTypeChanged(const QString& text) override;
virtual void TemporalFilterWidthChanged(double d) override;
virtual void TemporalFilterTypeChanged(const QString& text) override;
virtual void DEFilterMinRadiusWidthChanged(double d) override;
virtual void DEFilterMaxRadiusWidthChanged(double d) override;
virtual void DEFilterCurveWidthChanged(double d) override;
virtual void PassesChanged(int d) override;
virtual void TemporalSamplesChanged(int d) override;
virtual void QualityChanged(double d) override;
virtual void SupersampleChanged(int d) override;
virtual void AffineInterpTypeChanged(int index) override;
virtual void InterpTypeChanged(int index) override;
virtual void BackgroundChanged(const QColor& col) override;
//Xforms.
virtual void CurrentXformComboChanged(int index);
virtual void XformWeightChanged(double d);
virtual void EqualizeWeights();
virtual void XformNameChanged(int row, int col);
virtual void CurrentXformComboChanged(int index) override;
virtual void XformWeightChanged(double d) override;
virtual void EqualizeWeights() override;
virtual void XformNameChanged(int row, int col) override;
void FillWithXform(Xform<T>* xform);
Xform<T>* CurrentXform();
//Xforms Affine.
virtual void AffineSetHelper(double d, int index, bool pre);
virtual void FlipCurrentXform(bool horizontal, bool vertical, bool pre);
virtual void RotateCurrentXformByAngle(double angle, bool pre);
virtual void MoveCurrentXform(double x, double y, bool pre);
virtual void ScaleCurrentXform(double scale, bool pre);
virtual void ResetCurrentXformAffine(bool pre);
virtual void AffineSetHelper(double d, int index, bool pre) override;
virtual void FlipCurrentXform(bool horizontal, bool vertical, bool pre) override;
virtual void RotateCurrentXformByAngle(double angle, bool pre) override;
virtual void MoveCurrentXform(double x, double y, bool pre) override;
virtual void ScaleCurrentXform(double scale, bool pre) override;
virtual void ResetCurrentXformAffine(bool pre) override;
void FillAffineWithXform(Xform<T>* xform, bool pre);
//Xforms Color.
virtual void XformColorIndexChanged(double d, bool updateRender);
virtual void XformScrollColorIndexChanged(int d);
virtual void XformColorSpeedChanged(double d);
virtual void XformOpacityChanged(double d);
virtual void XformDirectColorChanged(double d);
virtual void XformColorIndexChanged(double d, bool updateRender) override;
virtual void XformScrollColorIndexChanged(int d) override;
virtual void XformColorSpeedChanged(double d) override;
virtual void XformOpacityChanged(double d) override;
virtual void XformDirectColorChanged(double d) override;
void FillColorWithXform(Xform<T>* xform);
//Xforms Variations.
virtual void SetupVariationTree();
virtual void ClearVariationsTree();
virtual void VariationSpinBoxValueChanged(double d);
virtual void SetupVariationTree() override;
virtual void ClearVariationsTree() override;
virtual void VariationSpinBoxValueChanged(double d) override;
void FillVariationTreeWithXform(Xform<T>* xform);
//Xforms Xaos.
virtual void FillXaosWithCurrentXform();
virtual QString MakeXaosNameString(unsigned int i);
virtual void XaosChanged(DoubleSpinBox* sender);
virtual void ClearXaos();
virtual void FillXaosWithCurrentXform() override;
virtual QString MakeXaosNameString(unsigned int i) override;
virtual void XaosChanged(DoubleSpinBox* sender) override;
virtual void ClearXaos() override;
//Palette.
virtual bool InitPaletteTable(string s);
virtual void ApplyPaletteToEmber();
virtual void PaletteAdjust();
virtual QRgb GetQRgbFromPaletteIndex(unsigned int i) { return QRgb(); }
virtual void PaletteCellClicked(int row, int col);
virtual bool InitPaletteTable(const string& s) override;
virtual void ApplyPaletteToEmber() override;
virtual void PaletteAdjust() override;
virtual QRgb GetQRgbFromPaletteIndex(unsigned int i) override { return QRgb(); }
virtual void PaletteCellClicked(int row, int col) override;
//Library.
virtual void SyncNames();
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(unsigned int start = UINT_MAX, unsigned int end = UINT_MAX);
virtual void StopPreviewRender();
virtual void SyncNames() override;
virtual void FillLibraryTree(int selectIndex = -1) override;
virtual void UpdateLibraryTree() override;
virtual void EmberTreeItemChanged(QTreeWidgetItem* item, int col) override;
virtual void EmberTreeItemDoubleClicked(QTreeWidgetItem* item, int col) override;
virtual void RenderPreviews(unsigned int start = UINT_MAX, unsigned int end = UINT_MAX) override;
virtual void StopPreviewRender() override;
//Info.
//Rendering/progress.
virtual bool Render();
virtual bool CreateRenderer(eRendererType renderType, unsigned int platform, unsigned int device, bool shared = true);
virtual unsigned int SizeOfT() { return sizeof(T); }
virtual int ProgressFunc(Ember<T>& ember, void* foo, double fraction, int stage, double etaMs);
virtual void ClearUndo();
virtual GLEmberControllerBase* GLController() { return m_GLController.get(); }
virtual bool Render() override;
virtual bool CreateRenderer(eRendererType renderType, unsigned int platform, unsigned int device, bool shared = true) override;
virtual unsigned int SizeOfT() const override { return sizeof(T); }
virtual int ProgressFunc(Ember<T>& ember, void* foo, double fraction, int stage, double etaMs) override;
virtual void ClearUndo() override;
virtual GLEmberControllerBase* GLController() override { return m_GLController.get(); }
private:
//Embers.
@ -424,6 +432,7 @@ private:
//Rendering/progress.
void Update(std::function<void (void)> func, bool updateRender = true, eProcessAction action = FULL_RENDER);
void UpdateCurrentXform(std::function<void (Xform<T>*)> func, bool updateRender = true, eProcessAction action = FULL_RENDER);
bool SyncSizes();
//Templated members.
bool m_PreviewRun;

View File

@ -24,7 +24,7 @@ void Fractorium::UpdateHistogramBounds()
ui.InfoBoundsLabelW->setText(QString(m_WString));
ui.InfoBoundsLabelH->setText(QString(m_HString));
ui.InfoBoundsTable->item(0, 1)->setText(QString::number(r->GutterWidth()));
ui.InfoBoundsTable->item(0, 1)->setText(ToString(r->GutterWidth()));
if (r->GetDensityFilter())
{
@ -54,5 +54,5 @@ void Fractorium::ErrorReportToQTextEdit(vector<string>& errors, QTextEdit* textE
QMetaObject::invokeMethod(textEdit, "clear", Qt::QueuedConnection);
for (size_t i = 0; i < errors.size(); i++)
QMetaObject::invokeMethod(textEdit, "append", Qt::QueuedConnection, Q_ARG(QString, QString::fromStdString(errors[i]) + "\n"));
QMetaObject::invokeMethod(textEdit, "append", Qt::QueuedConnection, Q_ARG(const QString&, QString::fromStdString(errors[i]) + "\n"));
}

View File

@ -38,7 +38,7 @@ void FractoriumEmberController<T>::SyncNames()
{
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.m_Embers.size())//Cast the child widget to the EmberTreeWidgetItem type.
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));
}
}
@ -72,7 +72,7 @@ void FractoriumEmberController<T>::FillLibraryTree(int selectIndex)
fileItem->setToolTip(0, m_EmberFile.m_Filename);
fileItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable);
for (j = 0; j < m_EmberFile.m_Embers.size(); j++)
for (j = 0; j < m_EmberFile.Size(); j++)
{
Ember<T>* ember = &m_EmberFile.m_Embers[j];
EmberTreeWidgetItem<T>* emberItem = new EmberTreeWidgetItem<T>(ember, fileItem);
@ -80,7 +80,7 @@ void FractoriumEmberController<T>::FillLibraryTree(int selectIndex)
emberItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable);
if (ember->m_Name.empty())
emberItem->setText(0, QString::number(j));
emberItem->setText(0, ToString(j));
else
emberItem->setText(0, ember->m_Name.c_str());
@ -96,7 +96,7 @@ void FractoriumEmberController<T>::FillLibraryTree(int selectIndex)
emberItem->setSelected(true);
QCoreApplication::flush();
RenderPreviews(0, m_EmberFile.m_Embers.size());
RenderPreviews(0, m_EmberFile.Size());
tree->expandAll();
}
@ -117,7 +117,7 @@ void FractoriumEmberController<T>::UpdateLibraryTree()
tree->blockSignals(true);
for (i = childCount; i < m_EmberFile.m_Embers.size(); i++)
for (i = childCount; i < m_EmberFile.Size(); i++)
{
Ember<T>* ember = &m_EmberFile.m_Embers[i];
EmberTreeWidgetItem<T>* emberItem = new EmberTreeWidgetItem<T>(ember, top);
@ -125,7 +125,7 @@ void FractoriumEmberController<T>::UpdateLibraryTree()
emberItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable);
if (ember->m_Name.empty())
emberItem->setText(0, QString::number(i));
emberItem->setText(0, ToString(i));
else
emberItem->setText(0, ember->m_Name.c_str());
@ -135,14 +135,14 @@ void FractoriumEmberController<T>::UpdateLibraryTree()
//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.
for (i = 0; i < m_EmberFile.m_Embers.size(); i++)
for (i = 0; i < m_EmberFile.Size(); i++)
{
if (EmberTreeWidgetItem<T>* emberItem = dynamic_cast<EmberTreeWidgetItem<T>*>(top->child(i)))
emberItem->SetEmberPointer(&m_EmberFile.m_Embers[i]);
}
tree->blockSignals(false);
RenderPreviews(childCount, m_EmberFile.m_Embers.size());
RenderPreviews(childCount, m_EmberFile.Size());
}
}
@ -250,7 +250,7 @@ void FractoriumEmberController<T>::RenderPreviews(unsigned int start, unsigned i
}
tree->blockSignals(false);
m_PreviewResult = QtConcurrent::run(m_PreviewRenderFunc, 0, m_EmberFile.m_Embers.size());
m_PreviewResult = QtConcurrent::run(m_PreviewRenderFunc, 0, m_EmberFile.Size());
}
else
m_PreviewResult = QtConcurrent::run(m_PreviewRenderFunc, start, end);

View File

@ -61,9 +61,10 @@ void FractoriumEmberController<T>::NewFlock(unsigned int count)
{
m_SheepTools->Random(ember);
ParamsToEmber(ember);
ember.m_Index = i;
ember.m_OrigFinalRasW = ember.m_FinalRasW;
ember.m_OrigFinalRasH = ember.m_FinalRasH;
ember.m_Name = m_EmberFile.m_Filename.toStdString() + "-" + QString::number(i + 1).toStdString();
ember.m_Name = m_EmberFile.m_Filename.toStdString() + "-" + ToString(i + 1).toStdString();
m_EmberFile.m_Embers.push_back(ember);
}
@ -102,11 +103,12 @@ void FractoriumEmberController<T>::NewEmptyFlameInCurrentFile()
xform.m_ColorX = m_Rand.Frand01<T>();
ember.AddXform(xform);
ember.m_Palette = *m_PaletteList.GetPalette(-1);
ember.m_Name = EmberFile<T>::DefaultEmberName(m_EmberFile.m_Embers.size() + 1).toStdString();
ember.m_Name = EmberFile<T>::DefaultEmberName(m_EmberFile.Size() + 1).toStdString();
ember.m_Index = m_EmberFile.Size();
m_EmberFile.m_Embers.push_back(ember);//Will invalidate the pointers contained in the EmberTreeWidgetItems, UpdateLibraryTree() will resync.
m_EmberFile.MakeNamesUnique();
UpdateLibraryTree();
SetEmber(m_EmberFile.m_Embers.size() - 1);
SetEmber(m_EmberFile.Size() - 1);
}
void Fractorium::OnActionNewEmptyFlameInCurrentFile(bool checked) { m_Controller->NewEmptyFlameInCurrentFile(); }
@ -126,11 +128,12 @@ void FractoriumEmberController<T>::NewRandomFlameInCurrentFile()
ParamsToEmber(ember);
ember.m_OrigFinalRasW = ember.m_FinalRasW;
ember.m_OrigFinalRasH = ember.m_FinalRasH;
ember.m_Name = EmberFile<T>::DefaultEmberName(m_EmberFile.m_Embers.size() + 1).toStdString();
ember.m_Name = EmberFile<T>::DefaultEmberName(m_EmberFile.Size() + 1).toStdString();
ember.m_Index = m_EmberFile.Size();
m_EmberFile.m_Embers.push_back(ember);//Will invalidate the pointers contained in the EmberTreeWidgetItems, UpdateLibraryTree() will resync.
m_EmberFile.MakeNamesUnique();
UpdateLibraryTree();
SetEmber(m_EmberFile.m_Embers.size() - 1);
SetEmber(m_EmberFile.Size() - 1);
}
void Fractorium::OnActionNewRandomFlameInCurrentFile(bool checked) { m_Controller->NewRandomFlameInCurrentFile(); }
@ -146,11 +149,12 @@ void FractoriumEmberController<T>::CopyFlameInCurrentFile()
Ember<T> ember = m_Ember;
StopPreviewRender();
ember.m_Name = EmberFile<T>::DefaultEmberName(m_EmberFile.m_Embers.size() + 1).toStdString();
ember.m_Name = EmberFile<T>::DefaultEmberName(m_EmberFile.Size() + 1).toStdString();
ember.m_Index = m_EmberFile.Size();
m_EmberFile.m_Embers.push_back(ember);//Will invalidate the pointers contained in the EmberTreeWidgetItems, UpdateLibraryTree() will resync.
m_EmberFile.MakeNamesUnique();
UpdateLibraryTree();
SetEmber(m_EmberFile.m_Embers.size() - 1);
SetEmber(m_EmberFile.Size() - 1);
}
void Fractorium::OnActionCopyFlameInCurrentFile(bool checked) { m_Controller->CopyFlameInCurrentFile(); }
@ -168,7 +172,7 @@ void Fractorium::OnActionCopyFlameInCurrentFile(bool checked) { m_Controller->Co
/// <param name="filenames">A list of full paths and filenames</param>
/// <param name="append">True to append the embers in the new files to the end of the currently open embers, false to clear and replace them</param>
template <typename T>
void FractoriumEmberController<T>::OpenAndPrepFiles(QStringList filenames, bool append)
void FractoriumEmberController<T>::OpenAndPrepFiles(const QStringList& filenames, bool append)
{
if (!filenames.empty())
{
@ -176,25 +180,24 @@ void FractoriumEmberController<T>::OpenAndPrepFiles(QStringList filenames, bool
EmberFile<T> emberFile;
XmlToEmber<T> parser;
vector<Ember<T>> embers;
unsigned int previousSize = append ? m_EmberFile.m_Embers.size() : 0;
unsigned int previousSize = append ? m_EmberFile.Size() : 0;
StopPreviewRender();
emberFile.m_Filename = filenames[0];
foreach (QString filename, filenames)
foreach(const QString& filename, filenames)
{
embers.clear();
if (parser.Parse(filename.toStdString().c_str(), embers) && !embers.empty())
{
//Disregard whatever size was specified in the file and fit it to the output window size.
for (i = 0; i < embers.size(); i++)
{
embers[i].SetSizeAndAdjustScale(m_Fractorium->ui.GLDisplay->width(), m_Fractorium->ui.GLDisplay->height(), true, SCALE_WIDTH);
ConstrainDimensions(embers[i]);//Do not exceed the max texture size.
//Also ensure it has a name.
if (embers[i].m_Name == "" || embers[i].m_Name == "No name")
embers[i].m_Name = QString::number(i).toStdString();
embers[i].m_Name = ToString(i).toStdString();
embers[i].m_Quality = m_Fractorium->m_QualitySpin->value();
embers[i].m_Supersample = m_Fractorium->m_SupersampleSpin->value();
@ -208,7 +211,7 @@ void FractoriumEmberController<T>::OpenAndPrepFiles(QStringList filenames, bool
vector<string> errors = parser.ErrorReport();
m_Fractorium->ErrorReportToQTextEdit(errors, m_Fractorium->ui.InfoFileOpeningTextEdit);
QMessageBox::critical(m_Fractorium, "Open Failed", "Could not open file, see info tab for details.");
m_Fractorium->ShowCritical("Open Failed", "Could not open file, see info tab for details.");
}
}
@ -223,7 +226,7 @@ void FractoriumEmberController<T>::OpenAndPrepFiles(QStringList filenames, bool
m_EmberFile = emberFile;
//Resync indices and names.
for (i = 0; i < m_EmberFile.m_Embers.size(); i++)
for (i = 0; i < m_EmberFile.Size(); i++)
m_EmberFile.m_Embers[i].m_Index = i;
m_EmberFile.MakeNamesUnique();
@ -261,7 +264,7 @@ void FractoriumEmberController<T>::SaveCurrentAsXml()
}
else
{
if (m_EmberFile.m_Embers.size() == 1)
if (m_EmberFile.Size() == 1)
filename = m_Fractorium->SetupSaveXmlDialog(m_EmberFile.m_Filename);//If only one ember present, just use parent filename.
else
filename = m_Fractorium->SetupSaveXmlDialog(QString::fromStdString(m_Ember.m_Name));//More than one ember present, use individual ember name.
@ -287,7 +290,7 @@ void FractoriumEmberController<T>::SaveCurrentAsXml()
m_LastSaveCurrent = filename;
}
else
QMessageBox::critical(m_Fractorium, "Save Failed", "Could not save file, try saving to a different folder.");
m_Fractorium->ShowCritical("Save Failed", "Could not save file, try saving to a different folder.");
}
}
@ -318,7 +321,7 @@ void FractoriumEmberController<T>::SaveEntireFileAsXml()
SaveCurrentToOpenedFile();//Save the current ember back to the opened file before writing to disk.
emberFile = m_EmberFile;
for (size_t i = 0; i < emberFile.m_Embers.size(); i++)
for (size_t i = 0; i < emberFile.Size(); i++)
ApplyXmlSavingTemplate(emberFile.m_Embers[i]);
if (writer.Save(filename.toStdString().c_str(), emberFile.m_Embers, 0, true, false, true))
@ -327,7 +330,7 @@ void FractoriumEmberController<T>::SaveEntireFileAsXml()
s->SaveFolder(fileInfo.canonicalPath());
}
else
QMessageBox::critical(m_Fractorium, "Save Failed", "Could not save file, try saving to a different folder.");
m_Fractorium->ShowCritical("Save Failed", "Could not save file, try saving to a different folder.");
}
}
@ -339,9 +342,9 @@ void Fractorium::OnActionSaveEntireFileAsXml(bool checked) { m_Controller->SaveE
/// <param name="checked">Ignored</param>
void Fractorium::OnActionSaveCurrentScreen(bool checked)
{
QString filename = SetupSaveImageDialog(QString::fromStdString(m_Controller->Name()));
QString filename = SetupSaveImageDialog(m_Controller->Name());
m_Controller->SaveCurrentRender(filename);
m_Controller->SaveCurrentRender(filename, true);
}
/// <summary>
@ -354,9 +357,10 @@ void FractoriumEmberController<T>::SaveCurrentToOpenedFile()
size_t i;
bool fileFound = false;
for (i = 0; i < m_EmberFile.m_Embers.size(); i++)
for (i = 0; i < m_EmberFile.Size(); i++)
{
if (m_Ember.m_Name == m_EmberFile.m_Embers[i].m_Name)
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))
{
m_EmberFile.m_Embers[i] = m_Ember;
fileFound = true;
@ -450,8 +454,6 @@ void FractoriumEmberController<T>::CopyXml()
EmberToXml<T> emberToXml;
FractoriumSettings* settings = m_Fractorium->m_Settings;
ember.m_FinalRasW = settings->XmlWidth();
ember.m_FinalRasH = settings->XmlHeight();
ember.m_Quality = settings->XmlQuality();
ember.m_Supersample = settings->XmlSupersample();
ember.m_TemporalSamples = settings->XmlTemporalSamples();
@ -473,16 +475,11 @@ void FractoriumEmberController<T>::CopyAllXml()
os << "<flames>\n";
for (size_t i = 0; i < m_EmberFile.m_Embers.size(); i++)
for (size_t i = 0; i < m_EmberFile.Size(); i++)
{
Ember<T> ember = m_EmberFile.m_Embers[i];
ember.m_FinalRasW = settings->XmlWidth();
ember.m_FinalRasH = settings->XmlHeight();
ember.m_Quality = settings->XmlQuality();
ember.m_Supersample = settings->XmlSupersample();
ember.m_TemporalSamples = settings->XmlTemporalSamples();
ApplyXmlSavingTemplate(ember);
os << emberToXml.ToString(ember, "", 0, false, false, true);
}
@ -502,7 +499,7 @@ void Fractorium::OnActionCopyAllXml(bool checked) { m_Controller->CopyAllXml();
template <typename T>
void FractoriumEmberController<T>::PasteXmlAppend()
{
unsigned int i, previousSize = m_EmberFile.m_Embers.size();
unsigned int i, previousSize = m_EmberFile.Size();
string s, errors;
XmlToEmber<T> parser;
vector<Ember<T>> embers;
@ -524,20 +521,19 @@ void FractoriumEmberController<T>::PasteXmlAppend()
if (errors != "")
{
QMessageBox::critical(m_Fractorium, "Paste Error", QString::fromStdString(errors));
m_Fractorium->ShowCritical("Paste Error", QString::fromStdString(errors));
}
if (!embers.empty())
{
for (i = 0; i < embers.size(); i++)
{
//Disregard whatever size was specified in the file and fit it to the output window size.
embers[i].m_Index = m_EmberFile.m_Embers.size();
embers[i].SetSizeAndAdjustScale(m_Fractorium->ui.GLDisplay->width(), m_Fractorium->ui.GLDisplay->height(), true, SCALE_WIDTH);
embers[i].m_Index = m_EmberFile.Size();
ConstrainDimensions(embers[i]);//Do not exceed the max texture size.
//Also ensure it has a name.
if (embers[i].m_Name == "" || embers[i].m_Name == "No name")
embers[i].m_Name = QString::number(embers[i].m_Index).toStdString();
embers[i].m_Name = ToString(embers[i].m_Index).toStdString();
m_EmberFile.m_Embers.push_back(embers[i]);//Will invalidate the pointers contained in the EmberTreeWidgetItems, UpdateLibraryTree() will resync.
}
@ -581,20 +577,19 @@ void FractoriumEmberController<T>::PasteXmlOver()
if (errors != "")
{
QMessageBox::critical(m_Fractorium, "Paste Error", QString::fromStdString(errors));
m_Fractorium->ShowCritical("Paste Error", QString::fromStdString(errors));
}
if (!m_EmberFile.m_Embers.empty())
if (m_EmberFile.Size())
{
for (i = 0; i < m_EmberFile.m_Embers.size(); i++)
for (i = 0; i < m_EmberFile.Size(); i++)
{
//Disregard whatever size was specified in the file and fit it to the output window size.
m_EmberFile.m_Embers[i].m_Index = i;
m_EmberFile.m_Embers[i].SetSizeAndAdjustScale(m_Fractorium->ui.GLDisplay->width(), m_Fractorium->ui.GLDisplay->height(), true, SCALE_WIDTH);
ConstrainDimensions(m_EmberFile.m_Embers[i]);//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 = QString::number(m_EmberFile.m_Embers[i].m_Index).toStdString();
m_EmberFile.m_Embers[i].m_Name = ToString(m_EmberFile.m_Embers[i].m_Index).toStdString();
}
}
else
@ -729,6 +724,7 @@ void Fractorium::OnActionFinalRender(bool checked)
{
//First completely stop what the current rendering process is doing.
m_Controller->DeleteRenderer();//Delete the renderer, but not the controller.
OnActionSaveCurrentToOpenedFile(true);//Save whatever was edited back to the current open file.
m_RenderStatusLabel->setText("Renderer stopped.");
m_FinalRenderDialog->show();
}

View File

@ -37,7 +37,7 @@ void Fractorium::InitPaletteUI()
/// <param name="s">The full path to the palette file</param>
/// <returns>True if successful, else false.</returns>
template <typename T>
bool FractoriumEmberController<T>::InitPaletteTable(string s)
bool FractoriumEmberController<T>::InitPaletteTable(const string& s)
{
QTableWidget* paletteTable = m_Fractorium->ui.PaletteListTable;
QTableWidget* palettePreviewTable = m_Fractorium->ui.PalettePreviewTable;
@ -93,7 +93,7 @@ bool FractoriumEmberController<T>::InitPaletteTable(string s)
vector<string> errors = m_PaletteList.ErrorReport();
m_Fractorium->ErrorReportToQTextEdit(errors, m_Fractorium->ui.InfoFileOpeningTextEdit);
QMessageBox::critical(m_Fractorium, "Palette Read Error", "Could not load palette file, all images will be black. See info tab for details.");
m_Fractorium->ShowCritical("Palette Read Error", "Could not load palette file, all images will be black. See info tab for details.");
}
return false;

View File

@ -45,8 +45,8 @@ void Fractorium::InitParamsUI()
//Geometry.
row = 0;
table = ui.GeometryTable;
SetupSpinner<SpinBox, int> (table, this, row, 1, m_WidthSpin, spinHeight, 10, 100000, 50, SIGNAL(valueChanged(int)), SLOT(OnWidthChanged(int)));
SetupSpinner<SpinBox, int> (table, this, row, 1, m_HeightSpin, spinHeight, 10, 100000, 50, SIGNAL(valueChanged(int)), SLOT(OnHeightChanged(int)));
SetupSpinner<SpinBox, int> (table, this, row, 1, m_WidthSpin, spinHeight, 10, 2048, 50, SIGNAL(valueChanged(int)), SLOT(OnWidthChanged(int)), true, width(), width(), width());
SetupSpinner<SpinBox, int> (table, this, row, 1, m_HeightSpin, spinHeight, 10, 2048, 50, SIGNAL(valueChanged(int)), SLOT(OnHeightChanged(int)), true, height(), height(), height());
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_CenterXSpin, spinHeight, -dmax, dmax, 0.05, SIGNAL(valueChanged(double)), SLOT(OnCenterXChanged(double)), true, 0, 0, 0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_CenterYSpin, spinHeight, -dmax, dmax, 0.05, SIGNAL(valueChanged(double)), SLOT(OnCenterYChanged(double)), true, 0, 0, 0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_ScaleSpin, spinHeight, 10, dmax, 20, SIGNAL(valueChanged(double)), SLOT(OnScaleChanged(double)), true, 240, 240, 240);
@ -57,8 +57,8 @@ void Fractorium::InitParamsUI()
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_PitchSpin, spinHeight, -180, 180, 1, SIGNAL(valueChanged(double)), SLOT(OnPitchChanged(double)), true, 0, 45, 0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_YawSpin, spinHeight, -180, 180, 1, SIGNAL(valueChanged(double)), SLOT(OnYawChanged(double)), true, 0, 45, 0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_DepthBlurSpin, spinHeight, -100, 100, 0.01, SIGNAL(valueChanged(double)), SLOT(OnDepthBlurChanged(double)), true, 0, 1, 0);
m_WidthSpin->setEnabled(false);//Will programatically change these to match the window size, but the user should never be allowed to.
m_HeightSpin->setEnabled(false);
//Set w/h max values.
m_CenterXSpin->setDecimals(3);
m_CenterYSpin->setDecimals(3);
m_ZPosSpin->setDecimals(3);
@ -178,9 +178,9 @@ void FractoriumEmberController<T>::BackgroundChanged(const QColor& color)
QTableWidget* colorTable = m_Fractorium->ui.ColorTable;
colorTable->item(itemRow, 1)->setBackgroundColor(color);
QString r = QString::number(color.red());
QString g = QString::number(color.green());
QString b = QString::number(color.blue());
QString r = ToString(color.red());
QString g = ToString(color.green());
QString b = ToString(color.blue());
int threshold = 105;
int delta = (color.red() * 0.299) + //Magic numbers gotten from a Stack Overflow post.
@ -218,14 +218,16 @@ void Fractorium::OnPaletteModeComboCurrentIndexChanged(int index) { m_Controller
/// Dimensions are set automatically to match the dimensions of GLWidget.
/// </summary>
/// <param name="d">Ignored</param>
void Fractorium::OnWidthChanged(int d) { }
template <typename T> void FractoriumEmberController<T>::WidthChanged(unsigned int i) { Update([&] { m_Ember.m_FinalRasW = i; }); }
void Fractorium::OnWidthChanged(int i) { m_Controller->WidthChanged(i); }
/// <summary>
/// Placeholder, do nothing.
/// Dimensions are set automatically to match the dimensions of GLWidget.
/// </summary>
/// <param name="d">Ignored</param>
void Fractorium::OnHeightChanged(int d) { }
template <typename T> void FractoriumEmberController<T>::HeightChanged(unsigned int i) { Update([&] { m_Ember.m_FinalRasH = i; }); }
void Fractorium::OnHeightChanged(int i) { m_Controller->HeightChanged(i); }
/// <summary>
/// Set the x offset applied to the center of the image.

View File

@ -27,6 +27,7 @@
#include <QItemDelegate>
#include <QApplication>
#include <QSettings>
#include <QStandardPaths>
#include <QGLWidget>
#include <QOpenGLFunctions_2_0.h>
#include <QtWidgets/QMainWindow>

View File

@ -102,14 +102,14 @@ void FractoriumEmberControllerBase::DeleteRenderer()
}
/// <summary>
/// Save the current contents of the GL window to a file.
/// Save the current render results to a file.
/// This could benefit from QImageWriter, however it's compression capabilities are
/// severely lacking. A Png file comes out larger than a bitmap, so instead use the
/// Png and Jpg wrapper functions from the command line programs.
/// This will embed the id, url and nick fields from the options in the image comments.
/// </summary>
/// <param name="filename">The full path and filename</param>
void FractoriumEmberControllerBase::SaveCurrentRender(QString filename)
void FractoriumEmberControllerBase::SaveCurrentRender(const QString& filename, bool forcePull)
{
if (filename != "")
{
@ -124,15 +124,22 @@ void FractoriumEmberControllerBase::SaveCurrentRender(QString filename)
FractoriumSettings* settings = m_Fractorium->m_Settings;
RendererCLBase* rendererCL = dynamic_cast<RendererCLBase*>(m_Renderer.get());
if (rendererCL && m_Renderer->PrepFinalAccumVector(m_FinalImage))
if (forcePull && rendererCL && m_Renderer->PrepFinalAccumVector(m_FinalImage))
{
if (!rendererCL->ReadFinal(m_FinalImage.data()))
{
QMessageBox::critical(m_Fractorium, "GPU Read Error", "Could not read image from the GPU, aborting image save.");
m_Fractorium->ShowCritical("GPU Read Error", "Could not read image from the GPU, aborting image save.", true);
return;
}
}
//Ensure dimensions are valid.
if (m_FinalImage.size() < (width * height * m_Renderer->NumChannels() * m_Renderer->BytesPerChannel()))
{
m_Fractorium->ShowCritical("Save Failed", "Dimensions didn't match, not saving.", true);
return;
}
data = m_FinalImage.data();//Png and channels = 4.
if ((suffix == "jpg" || suffix == "bmp") && m_Renderer->NumChannels() == 4)
@ -146,7 +153,7 @@ void FractoriumEmberControllerBase::SaveCurrentRender(QString filename)
string id = settings->Id().toStdString();
string url = settings->Url().toStdString();
string nick = settings->Nick().toStdString();
EmberImageComments comments = m_Renderer->ImageComments(0, false, true);
EmberImageComments comments = m_Renderer->ImageComments(m_Stats, 0, false, true);
if (suffix == "png")
b = WritePng(s.c_str(), data, width, height, 1, true, comments, id, url, nick);
@ -155,12 +162,15 @@ void FractoriumEmberControllerBase::SaveCurrentRender(QString filename)
else if (suffix == "bmp")
b = WriteBmp(s.c_str(), data, width, height);
else
QMessageBox::critical(m_Fractorium, "Save Failed", "Unrecognized format " + suffix + ", not saving.");
{
m_Fractorium->ShowCritical("Save Failed", "Unrecognized format " + suffix + ", not saving.", true);
return;
}
if (b)
settings->SaveFolder(fileInfo.canonicalPath());
else
QMessageBox::critical(m_Fractorium, "Save Failed", "Could not save file, try saving to a different folder.");
m_Fractorium->ShowCritical("Save Failed", "Could not save file, try saving to a different folder.", true);
}
}
@ -241,27 +251,56 @@ void FractoriumEmberController<T>::ClearUndo()
m_Fractorium->ui.ActionRedo->setEnabled(false);
}
/// <summary>
/// The hierarchy/order of sizes is like so:
/// Ember
/// GL Widget
/// Texture (passed to RendererCL)
/// Viewport
/// Since this uses m_GL->SizesMatch(), which uses the renderer's dimensions, this
/// must be called after the renderer has set the current ember.
/// </summary>
/// <returns>True if dimensions had to be resized due to a mismatch, else false.</returns>
template <typename T>
bool FractoriumEmberController<T>::SyncSizes()
{
bool changed = false;
GLWidget* gl = m_Fractorium->ui.GLDisplay;
RendererCL<T>* rendererCL;
if (!m_GLController->SizesMatch())
{
m_GLController->ClearWindow();
gl->SetDimensions(m_Ember.m_FinalRasW, m_Ember.m_FinalRasH);
gl->Allocate();
gl->SetViewport();
if (m_Renderer->RendererType() == OPENCL_RENDERER && (rendererCL = (RendererCL<T>*)m_Renderer.get()))
rendererCL->SetOutputTexture(gl->OutputTexID());
changed = true;
}
return changed;
}
/// <summary>
/// The main rendering function.
/// Called whenever the event loop is idle.
/// </summary>
/// <returns>True if nothing went wrong, else false.</returns>
template <typename T>
bool FractoriumEmberController<T>::Render()
{
bool success = true;
m_Rendering = true;
bool success = true;
GLWidget* gl = m_Fractorium->ui.GLDisplay;
RendererCL<T>* rendererCL;
eProcessAction action = CondenseAndClearProcessActions();
//Set dimensions first.
if ((m_Ember.m_FinalRasW != gl->width() ||
m_Ember.m_FinalRasH != gl->height()))
{
m_Ember.SetSizeAndAdjustScale(gl->width(), gl->height(), false, SCALE_WIDTH);
m_Fractorium->m_ScaleSpin->SetValueStealth(m_Ember.m_PixelsPerUnit);
action = FULL_RENDER;
}
if (m_Renderer->RendererType() == OPENCL_RENDERER)
rendererCL = (RendererCL<T>*)m_Renderer.get();
//Force temporal samples to always be 1. Perhaps change later when animation is implemented.
m_Ember.m_TemporalSamples = 1;
@ -293,6 +332,13 @@ bool FractoriumEmberController<T>::Render()
}
}
//Ensure sizes are equal and if not, update dimensions.
if (SyncSizes())
{
action = FULL_RENDER;
return true;
}
//Determining if a completely new rendering process is being started.
bool iterBegin = ProcessState() == NONE;
@ -332,11 +378,11 @@ bool FractoriumEmberController<T>::Render()
if (ProcessState() == ACCUM_DONE)
{
EmberStats stats = m_Renderer->Stats();
QString iters = ToString(stats.m_Iters);
QString scaledQuality = ToString((unsigned int)m_Renderer->ScaledQuality());
string renderTime = m_RenderElapsedTimer.Format(m_RenderElapsedTimer.Toc());
m_Fractorium->m_ProgressBar->setValue(100);
QString iters = QLocale(QLocale::English).toString(stats.m_Iters);
QString scaledQuality = QString::number((unsigned int)m_Renderer->ScaledQuality());
string renderTime = m_RenderElapsedTimer.Format(m_RenderElapsedTimer.Toc());
//Only certain status can be reported with OpenCL.
if (m_Renderer->RendererType() == OPENCL_RENDERER)
@ -346,8 +392,8 @@ bool FractoriumEmberController<T>::Render()
else
{
double percent = (double)stats.m_Badvals / (double)stats.m_Iters;
QString badVals = QLocale(QLocale::English).toString(stats.m_Badvals);
QString badPercent = QLocale(QLocale::English).toString(percent * 100, 'f', 2);
QString badVals = ToString(stats.m_Badvals);
QString badPercent = QLocale::system().toString(percent * 100, 'f', 2);
m_Fractorium->m_RenderStatusLabel->setText("Iters: " + iters + ". Scaled quality: " + scaledQuality + ". Bad values: " + badVals + " (" + badPercent + "%). Total time: " + QString::fromStdString(renderTime));
}
@ -385,7 +431,7 @@ bool FractoriumEmberController<T>::Render()
//Uncomment for debugging kernel build and execution errors.
//m_Fractorium->ui.InfoRenderingTextEdit->setText(QString::fromStdString(m_Fractorium->m_Wrapper.DumpInfo()));
//if (RendererCL<T>* rendererCL = dynamic_cast<RendererCL<T>*>(m_Renderer.get()))
//if (rendererCL)
// m_Fractorium->ui.InfoRenderingTextEdit->setText(QString::fromStdString(rendererCL->IterKernel()));
}
}
@ -404,11 +450,10 @@ bool FractoriumEmberController<T>::Render()
m_Rendering = false;
StopRenderTimer(true);
m_Fractorium->m_RenderStatusLabel->setText("Rendering failed 3 or more times, stopping all rendering, see info tab. Try changing renderer types.");
memset(m_FinalImage.data(), 0, m_FinalImage.size());
Memset(m_FinalImage);
if (m_Renderer->RendererType() == OPENCL_RENDERER)
((RendererCL<T>*)m_Renderer.get())->ClearFinal();
if (rendererCL)
rendererCL->ClearFinal();
m_GLController->ClearWindow();
}
@ -461,7 +506,7 @@ bool FractoriumEmberController<T>::CreateRenderer(eRendererType renderType, unsi
else
{
ok = false;
QMessageBox::critical(m_Fractorium, "Renderer Creation Error", "Could not create requested renderer, fallback CPU renderer created. See info tab for details.");
m_Fractorium->ShowCritical("Renderer Creation Error", "Could not create requested renderer, fallback CPU renderer created. See info tab for details.");
m_Fractorium->ErrorReportToQTextEdit(errorReport, m_Fractorium->ui.InfoRenderingTextEdit);
}
}
@ -503,7 +548,7 @@ bool FractoriumEmberController<T>::CreateRenderer(eRendererType renderType, unsi
else
{
ok = false;
QMessageBox::critical(m_Fractorium, "Renderer Creation Error", "Creating a basic CPU renderer failed, something is catastrophically wrong. Exiting program.");
m_Fractorium->ShowCritical("Renderer Creation Error", "Creating a basic CPU renderer failed, something is catastrophically wrong. Exiting program.");
QApplication::quit();
}
@ -525,7 +570,7 @@ bool Fractorium::CreateRendererFromOptions()
m_Settings->DeviceIndex()))
{
//If using OpenCL, will only get here if creating RendererCL failed, but creating a backup CPU Renderer succeeded.
QMessageBox::critical(this, "Renderer Creation Error", "Error creating renderer, most likely a GPU problem. Using CPU instead.");
ShowCritical("Renderer Creation Error", "Error creating renderer, most likely a GPU problem. Using CPU instead.");
m_Settings->OpenCL(false);
m_OptionsDialog->ui.OpenCLCheckBox->setChecked(false);
m_FinalRenderDialog->ui.FinalRenderOpenCLCheckBox->setChecked(false);

View File

@ -17,12 +17,6 @@ FractoriumSettings::FractoriumSettings(QObject* parent)
/// </summary>
void FractoriumSettings::EnsureDefaults()
{
if (FinalWidth() == 0)
FinalWidth(1920);
if (FinalHeight() == 0)
FinalHeight(1080);
if (FinalQuality() == 0)
FinalQuality(1000);
@ -32,11 +26,8 @@ void FractoriumSettings::EnsureDefaults()
if (FinalSupersample() == 0)
FinalSupersample(2);
if (XmlWidth() == 0)
XmlWidth(1920);
if (XmlHeight() == 0)
XmlHeight(1080);
if (FinalStrips() == 0)
FinalStrips(1);
if (XmlTemporalSamples() == 0)
XmlTemporalSamples(1000);
@ -89,8 +80,19 @@ void FractoriumSettings::EnsureDefaults()
if (SaveImageExt() == "")
SaveImageExt("Png (*.png)");
if (FinalDoAllExt() != "jpg" && FinalDoAllExt() != "png")
FinalDoAllExt("png");
if (FinalExt() != "jpg" && FinalExt() != "png")
FinalExt("png");
QString s = SaveFolder();
QDir dir(s);
if (s.isEmpty() || !dir.exists())
{
QStringList paths = QStandardPaths::standardLocations(QStandardPaths::DesktopLocation);
if (!paths.empty())
SaveFolder(paths[0]);
}
}
/// <summary>
@ -170,8 +172,8 @@ void FractoriumSettings::FinalKeepAspect(bool b) { setValue(FINALKEEPASPECT,
unsigned int FractoriumSettings::FinalScale() { return value(FINALSCALE).toUInt(); }
void FractoriumSettings::FinalScale(unsigned int i) { setValue(FINALSCALE, i); }
QString FractoriumSettings::FinalDoAllExt() { return value(FINALDOALLEXT).toString(); }
void FractoriumSettings::FinalDoAllExt(QString s) { setValue(FINALDOALLEXT, s); }
QString FractoriumSettings::FinalExt() { return value(FINALEXT).toString(); }
void FractoriumSettings::FinalExt(const QString& s) { setValue(FINALEXT, s); }
unsigned int FractoriumSettings::FinalPlatformIndex() { return value(FINALPLATFORMINDEX).toUInt(); }
void FractoriumSettings::FinalPlatformIndex(unsigned int i) { setValue(FINALPLATFORMINDEX, i); }
@ -182,12 +184,6 @@ void FractoriumSettings::FinalDeviceIndex(unsigned int i) { setValue(FINALDE
unsigned int FractoriumSettings::FinalThreadCount() { return value(FINALTHREADCOUNT).toUInt(); }
void FractoriumSettings::FinalThreadCount(unsigned int i) { setValue(FINALTHREADCOUNT, i); }
unsigned int FractoriumSettings::FinalWidth() { return value(FINALWIDTH).toUInt(); }
void FractoriumSettings::FinalWidth(unsigned int i) { setValue(FINALWIDTH, i); }
unsigned int FractoriumSettings::FinalHeight() { return value(FINALHEIGHT).toUInt(); }
void FractoriumSettings::FinalHeight(unsigned int i) { setValue(FINALHEIGHT, i); }
unsigned int FractoriumSettings::FinalQuality() { return value(FINALQUALITY).toUInt(); }
void FractoriumSettings::FinalQuality(unsigned int i) { setValue(FINALQUALITY, i); }
@ -197,15 +193,12 @@ void FractoriumSettings::FinalTemporalSamples(unsigned int i) { setValue(FINALTE
unsigned int FractoriumSettings::FinalSupersample() { return value(FINALSUPERSAMPLE).toUInt(); }
void FractoriumSettings::FinalSupersample(unsigned int i) { setValue(FINALSUPERSAMPLE, i); }
unsigned int FractoriumSettings::FinalStrips() { return value(FINALSTRIPS).toUInt(); }
void FractoriumSettings::FinalStrips(unsigned int i) { setValue(FINALSTRIPS, i); }
/// <summary>
/// Xml file saving settings.
/// </summary>
unsigned int FractoriumSettings::XmlWidth() { return value(XMLWIDTH).toUInt(); }
void FractoriumSettings::XmlWidth(unsigned int i) { setValue(XMLWIDTH, i); }
unsigned int FractoriumSettings::XmlHeight() { return value(XMLHEIGHT).toUInt(); }
void FractoriumSettings::XmlHeight(unsigned int i) { setValue(XMLHEIGHT, i); }
unsigned int FractoriumSettings::XmlTemporalSamples() { return value(XMLTEMPORALSAMPLES).toUInt(); }
void FractoriumSettings::XmlTemporalSamples(unsigned int i) { setValue(XMLTEMPORALSAMPLES, i); }
@ -217,32 +210,32 @@ unsigned int FractoriumSettings::XmlSupersample() { return value(XML
void FractoriumSettings::XmlSupersample(unsigned int i) { setValue(XMLSUPERSAMPLE, i); }
QString FractoriumSettings::Id() { return value(IDENTITYID).toString(); }
void FractoriumSettings::Id(QString s) { setValue(IDENTITYID, s); }
void FractoriumSettings::Id(const QString& s) { setValue(IDENTITYID, s); }
QString FractoriumSettings::Url() { return value(IDENTITYURL).toString(); }
void FractoriumSettings::Url(QString s) { setValue(IDENTITYURL, s); }
void FractoriumSettings::Url(const QString& s) { setValue(IDENTITYURL, s); }
QString FractoriumSettings::Nick() { return value(IDENTITYNICK).toString(); }
void FractoriumSettings::Nick(QString s) { setValue(IDENTITYNICK, s); }
void FractoriumSettings::Nick(const QString& s) { setValue(IDENTITYNICK, s); }
/// <summary>
/// General operations settings.
/// </summary>
QString FractoriumSettings::OpenFolder() { return value(OPENFOLDER).toString(); }
void FractoriumSettings::OpenFolder(QString s) { setValue(OPENFOLDER, s); }
void FractoriumSettings::OpenFolder(const QString& s) { setValue(OPENFOLDER, s); }
QString FractoriumSettings::SaveFolder() { return value(SAVEFOLDER).toString(); }
void FractoriumSettings::SaveFolder(QString s) { setValue(SAVEFOLDER, s); }
void FractoriumSettings::SaveFolder(const QString& s) { setValue(SAVEFOLDER, s); }
QString FractoriumSettings::OpenXmlExt() { return value(OPENXMLEXT).toString(); }
void FractoriumSettings::OpenXmlExt(QString s) { setValue(OPENXMLEXT, s); }
void FractoriumSettings::OpenXmlExt(const QString& s) { setValue(OPENXMLEXT, s); }
QString FractoriumSettings::SaveXmlExt() { return value(SAVEXMLEXT).toString(); }
void FractoriumSettings::SaveXmlExt(QString s) { setValue(SAVEXMLEXT, s); }
void FractoriumSettings::SaveXmlExt(const QString& s) { setValue(SAVEXMLEXT, s); }
QString FractoriumSettings::OpenImageExt() { return value(OPENIMAGEEXT).toString(); }
void FractoriumSettings::OpenImageExt(QString s) { setValue(OPENIMAGEEXT, s); }
void FractoriumSettings::OpenImageExt(const QString& s) { setValue(OPENIMAGEEXT, s); }
QString FractoriumSettings::SaveImageExt() { return value(SAVEIMAGEEXT).toString(); }
void FractoriumSettings::SaveImageExt(QString s) { setValue(SAVEIMAGEEXT, s); }
void FractoriumSettings::SaveImageExt(const QString& s) { setValue(SAVEIMAGEEXT, s); }

View File

@ -30,15 +30,14 @@
#define FINALDOSEQUENCE "finalrender/dosequence"
#define FINALKEEPASPECT "finalrender/keepaspect"
#define FINALSCALE "finalrender/scale"
#define FINALDOALLEXT "finalrender/doallext"
#define FINALEXT "finalrender/ext"
#define FINALPLATFORMINDEX "finalrender/platformindex"
#define FINALDEVICEINDEX "finalrender/deviceindex"
#define FINALTHREADCOUNT "finalrender/threadcount"
#define FINALWIDTH "finalrender/width"
#define FINALHEIGHT "finalrender/height"
#define FINALQUALITY "finalrender/quality"
#define FINALTEMPORALSAMPLES "finalrender/temporalsamples"
#define FINALSUPERSAMPLE "finalrender/supersample"
#define FINALSTRIPS "finalrender/strips"
#define XMLWIDTH "xml/width"
#define XMLHEIGHT "xml/height"
@ -139,8 +138,8 @@ public:
unsigned int FinalScale();
void FinalScale(unsigned int i);
QString FinalDoAllExt();
void FinalDoAllExt(QString s);
QString FinalExt();
void FinalExt(const QString& s);
unsigned int FinalPlatformIndex();
void FinalPlatformIndex(unsigned int b);
@ -151,12 +150,6 @@ public:
unsigned int FinalThreadCount();
void FinalThreadCount(unsigned int b);
unsigned int FinalWidth();
void FinalWidth(unsigned int i);
unsigned int FinalHeight();
void FinalHeight(unsigned int i);
unsigned int FinalQuality();
void FinalQuality(unsigned int i);
@ -166,11 +159,8 @@ public:
unsigned int FinalSupersample();
void FinalSupersample(unsigned int i);
unsigned int XmlWidth();
void XmlWidth(unsigned int i);
unsigned int XmlHeight();
void XmlHeight(unsigned int i);
unsigned int FinalStrips();
void FinalStrips(unsigned int i);
unsigned int XmlTemporalSamples();
void XmlTemporalSamples(unsigned int i);
@ -182,29 +172,29 @@ public:
void XmlSupersample(unsigned int i);
QString OpenFolder();
void OpenFolder(QString s);
void OpenFolder(const QString& s);
QString SaveFolder();
void SaveFolder(QString s);
void SaveFolder(const QString& s);
QString OpenXmlExt();
void OpenXmlExt(QString s);
void OpenXmlExt(const QString& s);
QString SaveXmlExt();
void SaveXmlExt(QString s);
void SaveXmlExt(const QString& s);
QString OpenImageExt();
void OpenImageExt(QString s);
void OpenImageExt(const QString& s);
QString SaveImageExt();
void SaveImageExt(QString s);
void SaveImageExt(const QString& s);
QString Id();
void Id(QString s);
void Id(const QString& s);
QString Url();
void Url(QString s);
void Url(const QString& s);
QString Nick();
void Nick(QString s);
void Nick(const QString& s);
};

View File

@ -334,7 +334,7 @@ void Fractorium::FillXforms()
for (i = 0; i < m_Controller->XformCount(); i++)
{
combo->addItem(QString::number(i + 1));
combo->addItem(ToString(i + 1));
combo->setItemIcon(i, m_XformComboIcons[i % XFORM_COLOR_COUNT]);
}

View File

@ -213,7 +213,7 @@ void Fractorium::OnRotateCButtonClicked(bool checked)
bool ok;
bool pre = sender() == ui.PreRotateCButton;
QComboBox* combo = pre ? ui.PreRotateCombo : ui.PostRotateCombo;
double d = combo->currentText().toDouble(&ok);
double d = ToDouble(combo->currentText(), &ok);
if (ok)
m_Controller->RotateCurrentXformByAngle(d, pre);
@ -230,7 +230,7 @@ void Fractorium::OnRotateCcButtonClicked(bool checked)
bool ok;
bool pre = sender() == ui.PreRotateCcButton;
QComboBox* combo = pre ? ui.PreRotateCombo : ui.PostRotateCombo;
double d = combo->currentText().toDouble(&ok);
double d = ToDouble(combo->currentText(), &ok);
if (ok)
m_Controller->RotateCurrentXformByAngle(-d, pre);
@ -267,7 +267,7 @@ void Fractorium::OnMoveUpButtonClicked(bool checked)
bool ok;
bool pre = sender() == ui.PreMoveUpButton;
QComboBox* combo = pre ? ui.PreMoveCombo : ui.PostMoveCombo;
double d = combo->currentText().toDouble(&ok);
double d = ToDouble(combo->currentText(), &ok);
if (ok)
m_Controller->MoveCurrentXform(0, d, pre);
@ -284,7 +284,7 @@ void Fractorium::OnMoveDownButtonClicked(bool checked)
bool ok;
bool pre = sender() == ui.PreMoveDownButton;
QComboBox* combo = pre ? ui.PreMoveCombo : ui.PostMoveCombo;
double d = combo->currentText().toDouble(&ok);
double d = ToDouble(combo->currentText(), &ok);
if (ok)
m_Controller->MoveCurrentXform(0, -d, pre);
@ -301,7 +301,7 @@ void Fractorium::OnMoveLeftButtonClicked(bool checked)
bool ok;
bool pre = sender() == ui.PreMoveLeftButton;
QComboBox* combo = pre ? ui.PreMoveCombo : ui.PostMoveCombo;
double d = combo->currentText().toDouble(&ok);
double d = ToDouble(combo->currentText(), &ok);
if (ok)
m_Controller->MoveCurrentXform(-d, 0, pre);
@ -318,7 +318,7 @@ void Fractorium::OnMoveRightButtonClicked(bool checked)
bool ok;
bool pre = sender() == ui.PreMoveRightButton;
QComboBox* combo = pre ? ui.PreMoveCombo : ui.PostMoveCombo;
double d = combo->currentText().toDouble(&ok);
double d = ToDouble(combo->currentText(), &ok);
if (ok)
m_Controller->MoveCurrentXform(d, 0, pre);
@ -356,7 +356,7 @@ void Fractorium::OnScaleDownButtonClicked(bool checked)
bool ok;
bool pre = sender() == ui.PreScaleDownButton;
QComboBox* combo = pre ? ui.PreScaleCombo : ui.PostScaleCombo;
double d = combo->currentText().toDouble(&ok);
double d = ToDouble(combo->currentText(), &ok);
if (ok)
m_Controller->ScaleCurrentXform(1.0 / (d / 100.0), pre);
@ -373,7 +373,7 @@ void Fractorium::OnScaleUpButtonClicked(bool checked)
bool ok;
bool pre = sender() == ui.PreScaleUpButton;
QComboBox* combo = pre ? ui.PreScaleCombo : ui.PostScaleCombo;
double d = combo->currentText().toDouble(&ok);
double d = ToDouble(combo->currentText(), &ok);
if (ok)
m_Controller->ScaleCurrentXform(d / 100.0, pre);

View File

@ -121,7 +121,7 @@ void Fractorium::OnSoloXformCheckBoxStateChanged(int state)
if (state == Qt::Checked)
{
ui.CurrentXformCombo->setProperty("soloxform", ui.CurrentXformCombo->currentIndex());
ui.SoloXformCheckBox->setText("Solo (" + QString::number(ui.CurrentXformCombo->currentIndex() + 1) + ")");
ui.SoloXformCheckBox->setText("Solo (" + ToString(ui.CurrentXformCombo->currentIndex() + 1) + ")");
}
else if (state == Qt::Unchecked)
{

View File

@ -62,9 +62,9 @@ QString FractoriumEmberController<T>::MakeXaosNameString(unsigned int i)
if (i != -1)
{
if (m_Fractorium->ui.XaosToRadio->isChecked())
name = QString("From ") + QString::number(curr) + QString(" To ") + QString::number(i);
name = QString("From ") + ToString(curr) + QString(" To ") + ToString(i);
else
name = QString("From ") + QString::number(i) + QString(" To ") + QString::number(curr);
name = QString("From ") + ToString(i) + QString(" To ") + ToString(curr);
//if (xform->m_Name != "")
// name = name + " (" + QString::fromStdString(xform->m_Name) + ")";

View File

@ -60,7 +60,7 @@ public:
virtual void MouseRelease(QMouseEvent* e) { }
virtual void MouseMove(QMouseEvent* e) { }
virtual void Wheel(QWheelEvent* e) { }
virtual bool SyncSizes() { return false; }
virtual bool SizesMatch() { return false; }
virtual bool CheckForSizeMismatch(int w, int h) { return true; }
virtual void QueryMatrices(bool print) { }
@ -86,16 +86,16 @@ class GLEmberController : public GLEmberControllerBase
public:
GLEmberController(Fractorium* fractorium, GLWidget* glWidget, FractoriumEmberController<T>* controller);
virtual ~GLEmberController();
virtual void DrawImage();
virtual void DrawAffines(bool pre, bool post);
virtual void ClearWindow();
virtual void MousePress(QMouseEvent* e);
virtual void MouseRelease(QMouseEvent* e);
virtual void MouseMove(QMouseEvent* e);
virtual void Wheel(QWheelEvent* e);
virtual void QueryMatrices(bool print);
virtual bool SyncSizes();
virtual bool CheckForSizeMismatch(int w, int h);
virtual void DrawImage() override;
virtual void DrawAffines(bool pre, bool post) override;
virtual void ClearWindow() override;
virtual void MousePress(QMouseEvent* e) override;
virtual void MouseRelease(QMouseEvent* e) override;
virtual void MouseMove(QMouseEvent* e) override;
virtual void Wheel(QWheelEvent* e) override;
virtual void QueryMatrices(bool print) override;
virtual bool SizesMatch() override;
virtual bool CheckForSizeMismatch(int w, int h) override;
T CalcScale();
T CalcRotation();

View File

@ -120,6 +120,7 @@ void GLEmberController<T>::ClearWindow()
m_GL->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_GL->glClearColor(ember->m_Background.r, ember->m_Background.g, ember->m_Background.b, 1.0);
m_GL->makeCurrent();
m_GL->swapBuffers();
m_GL->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@ -159,10 +160,13 @@ void GLWidget::SetMainWindow(Fractorium* f) { m_Fractorium = f; }
bool GLWidget::Init() { return m_Init; }
bool GLWidget::Drawing() { return m_Drawing; }
GLint GLWidget::MaxTexSize() { return m_MaxTexSize; }
GLuint GLWidget::OutputTexID() { return m_OutputTexID; }
/// <summary>
/// Initialize OpenGL, called once at startup after the main window constructor finishes.
/// Although it seems an awkward place to put some of this setup code, the dimensions of the
/// main window and its widgets are not fully initialized before this is called.
/// Once this is done, the render timer is started after a short delay.
/// Rendering is then clear to begin.
/// </summary>
@ -172,6 +176,20 @@ void GLWidget::initializeGL()
{
glClearColor(0.0, 0.0, 0.0, 1.0);
int w = m_Fractorium->ui.GLParentScrollArea->width();
int h = m_Fractorium->ui.GLParentScrollArea->height();
SetDimensions(w, h);
m_Fractorium->m_WidthSpin->setValue(w);
m_Fractorium->m_HeightSpin->setValue(h);
glEnable(GL_TEXTURE_2D);
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_MaxTexSize);
glDisable(GL_TEXTURE_2D);
m_Fractorium->m_WidthSpin->setMaximum(m_MaxTexSize);
m_Fractorium->m_HeightSpin->setMaximum(m_MaxTexSize);
//Start with a flock of 10 random embers. Can't do this until now because the window wasn't maximized yet, so the sizes would have been off.
m_Fractorium->OnActionNewFlock(false);
m_Fractorium->m_Controller->DelayedStartRenderTimer();
@ -193,9 +211,7 @@ void GLWidget::paintGL()
RendererBase* renderer = controller->Renderer();
m_Drawing = true;
//renderer->EnterResize();
controller->GLController()->DrawImage();
//renderer->LeaveResize();//Unlock, may not be necessary.
//Affine drawing.
bool pre = m_Fractorium->ui.PreAffineGroupBox->isChecked();
@ -244,23 +260,23 @@ void GLEmberController<T>::DrawImage()
{
RendererBase* renderer = m_FractoriumEmberController->Renderer();
Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
m_GL->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_GL->glClearColor(ember->m_Background.r, ember->m_Background.g, ember->m_Background.b, 1.0);
m_GL->glDisable(GL_DEPTH_TEST);
renderer->EnterFinalAccum();//Lock, may not be necessary, but just in case.
renderer->EnterResize();
if (SyncSizes())//Ensure all sizes are correct. If not, do nothing.
if (SizesMatch())//Ensure all sizes are correct. If not, do nothing.
{
vector<unsigned char>* finalImage = m_FractoriumEmberController->FinalImage();
if (renderer->RendererType() == OPENCL_RENDERER || finalImage)//Final image only matters for CPU renderer.
if (renderer->RendererType() == OPENCL_RENDERER || finalImage->size() == renderer->FinalBufferSize())
m_GL->DrawQuad();//Output image is drawn here.
}
renderer->LeaveResize();//Unlock, may not be necessary.
renderer->LeaveFinalAccum();
}
@ -575,7 +591,7 @@ void GLEmberController<T>::MouseMove(QMouseEvent* e)
glm::ivec2 mouse(e->x(), e->y());
v3T mouseFlipped(e->x(), m_Viewport[3] - e->y(), 0);//Must flip y because in OpenGL, 0,0 is bottom left, but in windows, it's top left.
Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
//First check to see if the mouse actually moved.
if (mouse == m_MousePos)
return;
@ -650,7 +666,7 @@ void GLEmberController<T>::MouseMove(QMouseEvent* e)
//if (m_HoverXform == previousHover)
// draw = false;
}
//Only update if the user was dragging or hovered over a point.
//Use repaint() to update immediately for a more responsive feel.
if ((m_DragState != DragNone) || draw)
@ -665,10 +681,10 @@ void GLEmberController<T>::MouseMove(QMouseEvent* e)
void GLWidget::mouseMoveEvent(QMouseEvent* e)
{
setFocus();//Must do this so that this window gets keyboard events.
if (GLEmberControllerBase* controller = GLController())
controller->MouseMove(e);
QGLWidget::mouseMoveEvent(e);
}
@ -711,12 +727,21 @@ void GLWidget::resizeEvent(QResizeEvent* e)
{
if (m_Fractorium)
{
m_Fractorium->m_WidthSpin->setValue(width());
m_Fractorium->m_HeightSpin->setValue(height());
//qDebug() << "GLWidget::resizeEvent() : w, h: " << width() << ", " << height() << ". oldsize: " << e->oldSize().width() << ", " << e->oldSize().height();
//m_Fractorium->m_WidthSpin->setValue(width());
//m_Fractorium->m_HeightSpin->setValue(height());
if (GLEmberControllerBase* controller = GLController())
controller->SyncSizes();//For some reason the base resize can't be called here or else it causes a crash.
// if (GLEmberControllerBase* controller = GLController())
// controller->SyncSizes();//For some reason the base resize can't be called here or else it causes a crash.
}
//QGLWidget::resizeEvent(e);
}
void GLWidget::SetDimensions(int w, int h)
{
setFixedSize(w, h);
m_Fractorium->ui.GLParentScrollAreaContents->setFixedSize(w, h);
}
/// <summary>
@ -729,13 +754,22 @@ void GLWidget::resizeEvent(QResizeEvent* e)
bool GLWidget::Allocate(bool force)
{
bool alloc = false;
bool resize = force || m_TexWidth != width() || m_TexHeight != height();
bool doIt = resize || m_OutputTexID == 0;
if (m_OutputTexID == 0)
if (doIt)
{
m_TexWidth = width();
m_TexHeight = height();
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
if (resize)
{
glBindTexture(GL_TEXTURE_2D, m_OutputTexID);
Deallocate();
}
glGenTextures(1, &m_OutputTexID);
glBindTexture(GL_TEXTURE_2D, m_OutputTexID);
@ -746,28 +780,7 @@ bool GLWidget::Allocate(bool force)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_TexWidth, m_TexHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
alloc = true;
}
else
{
if (force || (m_TexWidth != width() || m_TexHeight != height()))
{
m_TexWidth = width();
m_TexHeight = height();
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glBindTexture(GL_TEXTURE_2D, m_OutputTexID);
Deallocate();
glGenTextures(1, &m_OutputTexID);
glBindTexture(GL_TEXTURE_2D, m_OutputTexID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//Fractron had this as GL_LINEAR_MIPMAP_LINEAR for OpenCL and Cuda.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_TexWidth, m_TexHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
alloc = true;
}
}
if (alloc)
{
glBindTexture(GL_TEXTURE_2D, 0);
@ -801,45 +814,33 @@ bool GLWidget::Deallocate()
/// </summary>
void GLWidget::SetViewport()
{
if (m_Init && (m_ViewWidth != width() || m_ViewHeight != height()))
if (m_Init && (m_ViewWidth != m_TexWidth || m_ViewHeight != m_TexHeight))
{
glViewport(0, 0, (GLint)width(), (GLint)height());
m_ViewWidth = width();
m_ViewHeight = height();
glViewport(0, 0, (GLint)m_TexWidth, (GLint)m_TexHeight);
m_ViewWidth = m_TexWidth;
m_ViewHeight = m_TexHeight;
}
}
/// <summary>
/// Synchronize the size of the renderer output image, the texture, and this window.
/// They must all match. If the renderer output size doesn't match, then the render
/// timer is stopped and restarted with a delay.
/// This will get called once or twice when a resize occurs.
/// Determine whether the dimensions of the renderer's current ember match
/// the dimensions of the widget, texture and viewport.
/// Since this uses the renderer's dimensions, this
/// must be called after the renderer has set the current ember.
/// </summary>
/// <returns>True if all sizes match, else false.</returns>
template <typename T>
bool GLEmberController<T>::SyncSizes()
bool GLEmberController<T>::SizesMatch()
{
if (m_GL->Init())
{
m_GL->SetViewport();
Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
//First make sure the dimensions of the ember match the window size.
if (CheckForSizeMismatch(m_GL->width(), m_GL->height()))
{
if (m_Fractorium)//This will stop the rendering process and start the reset timer.
m_Fractorium->Resize();
return false;
}
//The renderer and window dimensions match, now make sure the dims of the texture match.
if (!m_GL->Allocate())
return false;
return true;
}
return false;
return (ember &&
ember->m_FinalRasW == m_GL->width() &&
ember->m_FinalRasH == m_GL->height() &&
m_GL->width() == m_GL->m_TexWidth &&
m_GL->height() == m_GL->m_TexHeight &&
m_GL->m_TexWidth == m_GL->m_ViewWidth &&
m_GL->m_TexHeight == m_GL->m_ViewHeight);
}
/// <summary>

View File

@ -43,20 +43,22 @@ public:
void SetMainWindow(Fractorium* f);
bool Init();
bool Drawing();
GLint MaxTexSize();
GLuint OutputTexID();
protected:
virtual void initializeGL();
virtual void paintGL();
virtual void keyPressEvent(QKeyEvent* e);
virtual void keyReleaseEvent(QKeyEvent* e);
virtual void mousePressEvent(QMouseEvent* e);
virtual void mouseReleaseEvent(QMouseEvent* e);
virtual void mouseMoveEvent(QMouseEvent* e);
virtual void wheelEvent(QWheelEvent* e);
virtual void resizeEvent(QResizeEvent* e);
virtual void initializeGL() override;
virtual void paintGL() override;
virtual void keyPressEvent(QKeyEvent* e) override;
virtual void keyReleaseEvent(QKeyEvent* e) override;
virtual void mousePressEvent(QMouseEvent* e) override;
virtual void mouseReleaseEvent(QMouseEvent* e) override;
virtual void mouseMoveEvent(QMouseEvent* e) override;
virtual void wheelEvent(QWheelEvent* e) override;
virtual void resizeEvent(QResizeEvent* e) override;
private:
void SetDimensions(int w, int h);
bool Allocate(bool force = false);
bool Deallocate();
void SetViewport();
@ -67,6 +69,7 @@ private:
bool m_Init;
bool m_Drawing;
GLint m_MaxTexSize;
GLint m_TexWidth;
GLint m_TexHeight;
GLint m_ViewWidth;

View File

@ -21,11 +21,9 @@ FractoriumOptionsDialog::FractoriumOptionsDialog(FractoriumSettings* settings, Q
connect(ui.OpenCLCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnOpenCLCheckBoxStateChanged(int)), Qt::QueuedConnection);
connect(ui.PlatformCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(OnPlatformComboCurrentIndexChanged(int)), Qt::QueuedConnection);
SetupSpinner<SpinBox, int>(table, this, row, 1, m_XmlWidthSpin, spinHeight, 10, 100000, 50, "", "", true, 1920);
SetupSpinner<SpinBox, int>(table, this, row, 1, m_XmlHeightSpin, spinHeight, 10, 100000, 50, "", "", true, 1080);
SetupSpinner<SpinBox, int>(table, this, row, 1, m_XmlTemporalSamplesSpin, spinHeight, 1, 1000, 100, "", "", true, 1000);
SetupSpinner<SpinBox, int>(table, this, row, 1, m_XmlQualitySpin, spinHeight, 1, 200000, 50, "", "", true, 1000);
SetupSpinner<SpinBox, int>(table, this, row, 1, m_XmlSupersampleSpin, spinHeight, 1, 4, 1, "", "", true, 2);
SetupSpinner<SpinBox, int>(table, this, row, 1, m_XmlTemporalSamplesSpin, spinHeight, 1, 1000, 100, "", "", true, 1000);
SetupSpinner<SpinBox, int>(table, this, row, 1, m_XmlQualitySpin, spinHeight, 1, 200000, 50, "", "", true, 1000);
SetupSpinner<SpinBox, int>(table, this, row, 1, m_XmlSupersampleSpin, spinHeight, 1, 4, 1, "", "", true, 2);
m_IdEdit = new QLineEdit(ui.OptionsIdentityTable);
ui.OptionsIdentityTable->setCellWidget(0, 1, m_IdEdit);
@ -91,8 +89,6 @@ FractoriumOptionsDialog::FractoriumOptionsDialog(FractoriumSettings* settings, Q
ui.CpuSubBatchSpin->setValue(m_Settings->CpuSubBatch());
ui.OpenCLSubBatchSpin->setValue(m_Settings->OpenCLSubBatch());
m_XmlWidthSpin->setValue(m_Settings->XmlWidth());
m_XmlHeightSpin->setValue(m_Settings->XmlHeight());
m_XmlTemporalSamplesSpin->setValue(m_Settings->XmlTemporalSamples());
m_XmlQualitySpin->setValue(m_Settings->XmlQuality());
m_XmlSupersampleSpin->setValue(m_Settings->XmlSupersample());
@ -167,8 +163,6 @@ void FractoriumOptionsDialog::accept()
m_Settings->OpenCLDEFilter(ui.OpenCLFilteringDERadioButton->isChecked());
//Xml saving.
m_Settings->XmlWidth(m_XmlWidthSpin->value());
m_Settings->XmlHeight(m_XmlHeightSpin->value());
m_Settings->XmlTemporalSamples(m_XmlTemporalSamplesSpin->value());
m_Settings->XmlQuality(m_XmlQualitySpin->value());
m_Settings->XmlSupersample(m_XmlSupersampleSpin->value());
@ -203,8 +197,6 @@ void FractoriumOptionsDialog::reject()
ui.OpenCLFilteringDERadioButton->setChecked(m_Settings->OpenCLDEFilter());
//Xml saving.
m_XmlWidthSpin->setValue(m_Settings->XmlWidth());
m_XmlHeightSpin->setValue(m_Settings->XmlHeight());
m_XmlTemporalSamplesSpin->setValue(m_Settings->XmlTemporalSamples());
m_XmlQualitySpin->setValue(m_Settings->XmlQuality());
m_XmlSupersampleSpin->setValue(m_Settings->XmlSupersample());

View File

@ -46,8 +46,6 @@ private:
Ui::OptionsDialog ui;
OpenCLWrapper m_Wrapper;
SpinBox* m_XmlWidthSpin;
SpinBox* m_XmlHeightSpin;
SpinBox* m_XmlTemporalSamplesSpin;
SpinBox* m_XmlQualitySpin;
SpinBox* m_XmlSupersampleSpin;

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>300</width>
<height>411</height>
<height>347</height>
</rect>
</property>
<property name="sizePolicy">
@ -19,13 +19,13 @@
<property name="minimumSize">
<size>
<width>300</width>
<height>411</height>
<height>347</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>300</width>
<height>411</height>
<height>347</height>
</size>
</property>
<property name="windowTitle">
@ -67,7 +67,7 @@
</attribute>
<layout class="QFormLayout" name="formLayout">
<property name="verticalSpacing">
<number>6</number>
<number>4</number>
</property>
<property name="leftMargin">
<number>6</number>
@ -79,7 +79,7 @@
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
<number>4</number>
</property>
<item row="0" column="0">
<widget class="QCheckBox" name="EarlyClipCheckBox">
@ -324,13 +324,13 @@ in interactive mode for each mouse movement</string>
<property name="minimumSize">
<size>
<width>0</width>
<height>122</height>
<height>66</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>122</height>
<height>66</height>
</size>
</property>
<property name="focusPolicy">
@ -400,27 +400,17 @@ in interactive mode for each mouse movement</string>
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>24</number>
<number>22</number>
</attribute>
<attribute name="verticalHeaderHighlightSections">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderMinimumSectionSize">
<number>24</number>
<number>22</number>
</attribute>
<attribute name="verticalHeaderStretchLastSection">
<bool>false</bool>
</attribute>
<row>
<property name="text">
<string>Width</string>
</property>
</row>
<row>
<property name="text">
<string>Height</string>
</property>
</row>
<row>
<property name="text">
<string>Temporal Samples</string>
@ -448,7 +438,7 @@ in interactive mode for each mouse movement</string>
</column>
<item row="0" column="0">
<property name="text">
<string>Width</string>
<string>Temporal Samples</string>
</property>
<property name="flags">
<set>ItemIsDragEnabled|ItemIsUserCheckable|ItemIsEnabled</set>
@ -461,7 +451,7 @@ in interactive mode for each mouse movement</string>
</item>
<item row="1" column="0">
<property name="text">
<string>Height</string>
<string>Quality</string>
</property>
<property name="flags">
<set>ItemIsDragEnabled|ItemIsUserCheckable|ItemIsEnabled</set>
@ -473,32 +463,6 @@ in interactive mode for each mouse movement</string>
</property>
</item>
<item row="2" column="0">
<property name="text">
<string>Temporal Samples</string>
</property>
<property name="flags">
<set>ItemIsDragEnabled|ItemIsUserCheckable|ItemIsEnabled</set>
</property>
</item>
<item row="2" column="1">
<property name="text">
<string>0</string>
</property>
</item>
<item row="3" column="0">
<property name="text">
<string>Quality</string>
</property>
<property name="flags">
<set>ItemIsDragEnabled|ItemIsUserCheckable|ItemIsEnabled</set>
</property>
</item>
<item row="3" column="1">
<property name="text">
<string>0</string>
</property>
</item>
<item row="4" column="0">
<property name="text">
<string>Supersample</string>
</property>
@ -506,7 +470,7 @@ in interactive mode for each mouse movement</string>
<set>ItemIsDragEnabled|ItemIsUserCheckable|ItemIsEnabled</set>
</property>
</item>
<item row="4" column="1">
<item row="2" column="1">
<property name="text">
<string>0</string>
</property>
@ -543,13 +507,13 @@ in interactive mode for each mouse movement</string>
<property name="minimumSize">
<size>
<width>120</width>
<height>74</height>
<height>66</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>74</height>
<height>66</height>
</size>
</property>
<property name="focusPolicy">
@ -619,13 +583,13 @@ in interactive mode for each mouse movement</string>
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>24</number>
<number>22</number>
</attribute>
<attribute name="verticalHeaderHighlightSections">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderMinimumSectionSize">
<number>24</number>
<number>22</number>
</attribute>
<attribute name="verticalHeaderStretchLastSection">
<bool>false</bool>

View File

@ -4,7 +4,7 @@
#include "DoubleSpinBox.h"
/// <summary>
/// TwoButtonWidget and SpinnerButtonWidget classes.
/// TwoButtonComboWidget and SpinnerButtonWidget classes.
/// </summary>
/// <summary>
@ -12,7 +12,7 @@
/// Used for when a layout expects a single widget, but two need to go in its place.
/// The buttons are public so the caller can easily use them individually.
/// </summary>
class TwoButtonWidget : public QWidget
class TwoButtonComboWidget : public QWidget
{
Q_OBJECT
@ -27,12 +27,15 @@ public:
/// <param name="w2">The width of the second button</param>
/// <param name="h">The height of both buttons</param>
/// <param name="parent">The parent widget</param>
TwoButtonWidget(QString caption1, QString caption2, int w1, int w2, int h, QWidget* parent)
TwoButtonComboWidget(const QString& caption1, const QString& caption2, QStringList comboStrings, int w1, int w2, int h, QWidget* parent)
: QWidget(parent)
{
QHBoxLayout* layout = new QHBoxLayout(this);
m_Button1 = new QPushButton(caption1, parent);
m_Button2 = new QPushButton(caption2, parent);
m_Combo = new QComboBox(parent);
m_Combo->addItems(comboStrings);
if (w1 != -1)
{
@ -50,7 +53,10 @@ public:
m_Button1->setMaximumHeight(h);
m_Button2->setMinimumHeight(h);
m_Button2->setMaximumHeight(h);
m_Combo->setMinimumHeight(h - 3);
m_Combo->setMaximumHeight(h - 3);
layout->addWidget(m_Combo);
layout->addWidget(m_Button1);
layout->addWidget(m_Button2);
layout->setAlignment(Qt::AlignLeft);
@ -62,6 +68,7 @@ public:
QPushButton* m_Button1;
QPushButton* m_Button2;
QComboBox* m_Combo;
};
/// <summary>

View File

@ -4,7 +4,7 @@
#include "DoubleSpinBox.h"
/// <summary>
/// TwoButtonWidget class.
/// VariationTreeWidgetItem class.
/// </summary>
/// <summary>