Add texture saving dialog

This commit is contained in:
baldurk
2016-10-12 00:26:15 +02:00
parent f0c359b329
commit fbcb04944d
10 changed files with 1185 additions and 13 deletions
+3 -1
View File
@@ -295,7 +295,7 @@ void RDDialog::show(QMenu *menu, QPoint pos)
}
}
void RDDialog::show(QDialog *dialog)
int RDDialog::show(QDialog *dialog)
{
dialog->setWindowModality(Qt::ApplicationModal);
dialog->show();
@@ -305,6 +305,8 @@ void RDDialog::show(QDialog *dialog)
loop.processEvents(QEventLoop::WaitForMoreEvents);
QCoreApplication::sendPostedEvents();
}
return dialog->result();
}
QMessageBox::StandardButton RDDialog::messageBox(QMessageBox::Icon icon, QWidget *parent,
+10 -1
View File
@@ -54,6 +54,15 @@ struct ILogLoadProgressListener
class MainWindow;
struct Formatter
{
static QString Format(float f) { return QString::number(f); }
static QString Format(double d) { return QString::number(d); }
static QString Format(uint32_t u) { return QString::number(u); }
static QString Format(uint16_t u) { return QString::number(u); }
static QString Format(int32_t i) { return QString::number(i); }
};
class CaptureContext
{
public:
@@ -258,7 +267,7 @@ class QMenu;
struct RDDialog
{
static void show(QMenu *menu, QPoint pos);
static void show(QDialog *dialog);
static int show(QDialog *dialog);
static QMessageBox::StandardButton messageBox(
QMessageBox::Icon, QWidget *parent, const QString &title, const QString &text,
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
@@ -0,0 +1,609 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2016 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#include "TextureSaveDialog.h"
#include <QColorDialog>
#include "Code/CaptureContext.h"
#include "ui_TextureSaveDialog.h"
TextureSaveDialog::TextureSaveDialog(const FetchTexture &t, const TextureSave &s, QWidget *parent)
: QDialog(parent), ui(new Ui::TextureSaveDialog)
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
ui->setupUi(this);
ui->fileFormat->clear();
// TODO
ui->fileFormat->addItems({"DDS", "PNG", "JPG", "BMP", "TGA", "HDR", "EXR"});
ui->alphaMap->addItems({"Discard", "Blend to Colour", "Blend to Checkerboard"});
tex = t;
saveData = s;
ui->jpegCompression->setValue(saveData.jpegQuality);
ui->alphaMap->setCurrentIndex((int)saveData.alpha);
ui->blackPoint->setText(Formatter::Format(saveData.comp.blackPoint));
ui->whitePoint->setText(Formatter::Format(saveData.comp.whitePoint));
for(uint32_t i = 0; i < tex.mips; i++)
ui->mipSelect->addItem(QString::number(i) + " - " + QString::number(qMax(1U, tex.width >> i)) +
"x" + QString::number(qMax(1U, tex.height >> i)));
ui->mipSelect->setCurrentIndex(saveData.mip >= 0 ? saveData.mip : 0);
for(uint32_t i = 0; i < tex.msSamp; i++)
ui->sampleSelect->addItem(QString("Sample %1").arg(i));
ui->sampleSelect->setCurrentIndex(qMin(
(int)tex.msSamp, (saveData.sample.sampleIndex == ~0U ? 0 : (int)saveData.sample.sampleIndex)));
if(saveData.sample.sampleIndex == ~0U)
{
ui->resolveSamples->setChecked(true);
}
else
{
ui->oneSample->setChecked(true);
}
const char *cubeFaces[] = {"X+", "X-", "Y+", "Y-", "Z+", "Z-"};
uint32_t numSlices = (qMax(1U, tex.depth) * tex.numSubresources) / tex.mips;
for(uint32_t i = 0; i < numSlices; i++)
{
if(tex.cubemap)
{
QString name = cubeFaces[i % 6];
if(numSlices > 6)
name = QString("[%1] %2").arg(i / 6).arg(
cubeFaces[i % 6]); // Front 1, Back 2, 3, 4 etc for cube arrays
ui->sliceSelect->addItem(name);
}
else
{
ui->sliceSelect->addItem(QString("Slice %1").arg(i));
}
}
ui->sliceSelect->setCurrentIndex(saveData.slice.sliceIndex >= 0 ? saveData.slice.sliceIndex : 0);
ui->gridWidth->setMaximum(tex.depth * tex.arraysize * tex.msSamp);
ui->mipGroup->setVisible(tex.mips > 1);
ui->sampleGroup->setVisible(tex.msSamp > 1);
ui->sliceGroup->setVisible(tex.depth > 1 || tex.arraysize > 1 || tex.msSamp > 1);
if(saveData.destType != eFileType_DDS)
{
ui->cubeCruciform->setEnabled(tex.cubemap && tex.arraysize == 6);
if(!ui->oneSlice->isChecked() && !ui->cubeCruciform->isEnabled())
ui->mapSlicesToGrid->setChecked(true);
}
ui->fileFormat->setCurrentIndex((int)saveData.destType);
adjustSize();
}
TextureSaveDialog::~TextureSaveDialog()
{
delete ui;
}
QString TextureSaveDialog::filename()
{
return ui->filename->text();
}
void TextureSaveDialog::SetFiletypeFromFilename()
{
QFileInfo path(ui->filename->text());
QString ext = path.suffix().toUpper();
// TODO
/*
foreach(var ft in(FileType[])Enum.GetValues(typeof(FileType)))
{
if(ft.ToString().ToUpperInvariant() == ext)
{
fileFormat.SelectedIndex = (int)ft;
break;
}
}
*/
}
void TextureSaveDialog::SetFilenameFromFiletype()
{
QFileInfo path(ui->filename->text());
QString ext = path.suffix().toUpper();
// TODO
/*
FileType[] types = (FileType[])Enum.GetValues(typeof(FileType));
string selectedExt = types[fileFormat.SelectedIndex].ToString().ToLowerInvariant();
if(selectedExt != filenameExt)
{
filename.Text = filename.Text.Substring(0, filename.Text.Length - filenameExt.Length);
filename.Text += selectedExt;
}
*/
}
void TextureSaveDialog::on_fileFormat_currentIndexChanged(int index)
{
saveData.destType = (FileType)ui->fileFormat->currentIndex();
ui->jpegCompression->setEnabled(saveData.destType == eFileType_JPG);
ui->alphaGroup->setVisible(saveData.destType != eFileType_HDR &&
saveData.destType != eFileType_EXR &&
saveData.destType != eFileType_DDS);
bool noAlphaFormat = (saveData.destType == eFileType_BMP || saveData.destType == eFileType_JPG);
ui->alphaMap->setEnabled(tex.format.compCount == 4 && noAlphaFormat);
ui->alphaCol->setEnabled(saveData.alpha == eAlphaMap_BlendToColour && tex.format.compCount == 4 &&
noAlphaFormat);
if(saveData.destType == eFileType_DDS)
{
ui->exportAllMips->setEnabled(true);
ui->exportAllMips->setChecked(true);
ui->exportAllSlices->setEnabled(true);
ui->exportAllSlices->setChecked(true);
ui->cubeCruciform->setEnabled(true);
ui->cubeCruciform->setChecked(false);
ui->gridWidth->setEnabled(false);
ui->mapSlicesToGrid->setEnabled(false);
ui->mapSlicesToGrid->setChecked(false);
}
else
{
ui->exportAllMips->setEnabled(false);
ui->oneMip->setChecked(true);
ui->oneSlice->setChecked(true);
}
SetFilenameFromFiletype();
adjustSize();
}
void TextureSaveDialog::on_jpegCompression_valueChanged(double arg1)
{
saveData.jpegQuality = (int)arg1;
}
void TextureSaveDialog::on_exportAllMips_toggled(bool)
{
if(m_Recurse)
return;
m_Recurse = true;
ui->oneMip->setChecked(!ui->exportAllMips->isChecked());
ui->mipSelect->setEnabled(ui->oneMip->isChecked());
m_Recurse = false;
}
void TextureSaveDialog::on_oneMip_toggled(bool checked)
{
if(m_Recurse)
return;
m_Recurse = true;
ui->exportAllMips->setChecked(!ui->oneMip->isChecked());
ui->mipSelect->setEnabled(ui->oneMip->isChecked());
if(saveData.destType != eFileType_DDS)
{
ui->oneMip->setChecked(true);
ui->exportAllMips->setChecked(false);
ui->mipSelect->setEnabled(true);
}
m_Recurse = false;
}
void TextureSaveDialog::on_mipSelect_currentIndexChanged(int index)
{
saveData.mip = index;
}
void TextureSaveDialog::on_mapSampleArray_toggled(bool checked)
{
if(m_Recurse)
return;
m_Recurse = true;
if(ui->mapSampleArray->isChecked())
{
ui->resolveSamples->setChecked(false);
ui->oneSample->setChecked(false);
}
else
{
ui->resolveSamples->setChecked(false);
ui->oneSample->setChecked(true);
}
ui->sampleSelect->setEnabled(ui->oneSample->isChecked());
m_Recurse = false;
}
void TextureSaveDialog::on_resolveSamples_toggled(bool checked)
{
if(m_Recurse)
return;
m_Recurse = true;
if(ui->resolveSamples->isChecked())
{
ui->mapSampleArray->setChecked(false);
ui->oneSample->setChecked(false);
}
else
{
ui->mapSampleArray->setChecked(false);
ui->oneSample->setChecked(true);
}
ui->sampleSelect->setEnabled(ui->oneSample->isChecked());
m_Recurse = false;
}
void TextureSaveDialog::on_oneSample_toggled(bool checked)
{
if(m_Recurse)
return;
m_Recurse = true;
if(ui->oneSample->isChecked())
{
ui->mapSampleArray->setChecked(false);
ui->resolveSamples->setChecked(false);
}
else
{
ui->mapSampleArray->setChecked(false);
ui->resolveSamples->setChecked(true);
}
ui->sampleSelect->setEnabled(ui->oneSample->isChecked());
m_Recurse = false;
}
void TextureSaveDialog::on_sampleSelect_currentIndexChanged(int index)
{
saveData.sample.sampleIndex = (uint32_t)index;
}
void TextureSaveDialog::on_exportAllSlices_toggled(bool checked)
{
if(m_Recurse)
return;
m_Recurse = true;
ui->oneSlice->setChecked(!ui->exportAllSlices->isChecked());
if(saveData.destType == eFileType_DDS)
{
ui->mapSlicesToGrid->setEnabled(false);
ui->gridWidth->setEnabled(false);
ui->cubeCruciform->setEnabled(false);
}
else
{
ui->mapSlicesToGrid->setEnabled(!ui->oneSlice->isChecked());
ui->gridWidth->setEnabled(!ui->oneSlice->isChecked());
if(!ui->oneSlice->isChecked() && !ui->cubeCruciform->isChecked())
ui->mapSlicesToGrid->setChecked(true);
if(tex.cubemap && tex.arraysize == 6)
ui->cubeCruciform->setEnabled(!ui->oneSlice->isChecked());
else
ui->cubeCruciform->setEnabled(false);
}
ui->sliceSelect->setEnabled(ui->oneSlice->isChecked());
m_Recurse = false;
}
void TextureSaveDialog::on_oneSlice_toggled(bool checked)
{
if(m_Recurse)
return;
m_Recurse = true;
ui->exportAllSlices->setChecked(!ui->oneSlice->isChecked());
if(saveData.destType == eFileType_DDS)
{
ui->mapSlicesToGrid->setEnabled(false);
ui->gridWidth->setEnabled(false);
ui->cubeCruciform->setEnabled(false);
}
else
{
ui->mapSlicesToGrid->setEnabled(!ui->oneSlice->isChecked());
ui->gridWidth->setEnabled(!ui->oneSlice->isChecked());
if(!ui->oneSlice->isChecked() && !ui->cubeCruciform->isChecked())
ui->mapSlicesToGrid->setChecked(true);
if(tex.cubemap && tex.arraysize == 6)
ui->cubeCruciform->setEnabled(!ui->oneSlice->isChecked());
else
ui->cubeCruciform->setEnabled(false);
}
ui->sliceSelect->setEnabled(ui->oneSlice->isChecked());
m_Recurse = false;
}
void TextureSaveDialog::on_mapSlicesToGrid_toggled(bool checked)
{
if(m_Recurse)
return;
m_Recurse = true;
if(ui->mapSlicesToGrid->isChecked())
{
ui->cubeCruciform->setChecked(false);
}
else if(saveData.destType != eFileType_DDS)
{
ui->oneSlice->setChecked(true);
ui->exportAllSlices->setChecked(false);
ui->cubeCruciform->setEnabled(false);
ui->mapSlicesToGrid->setEnabled(false);
ui->gridWidth->setEnabled(false);
ui->sliceSelect->setEnabled(true);
}
m_Recurse = false;
if(saveData.destType == eFileType_DDS)
ui->gridWidth->setEnabled(false);
else
ui->gridWidth->setEnabled(ui->mapSlicesToGrid->isChecked());
}
void TextureSaveDialog::on_cubeCruciform_toggled(bool checked)
{
if(m_Recurse)
return;
m_Recurse = true;
if(ui->cubeCruciform->isChecked())
{
ui->mapSlicesToGrid->setChecked(false);
}
else if(saveData.destType != eFileType_DDS)
{
ui->oneSlice->setChecked(true);
ui->exportAllSlices->setChecked(false);
ui->cubeCruciform->setEnabled(false);
ui->mapSlicesToGrid->setEnabled(false);
ui->gridWidth->setEnabled(false);
ui->sliceSelect->setEnabled(true);
}
m_Recurse = false;
}
void TextureSaveDialog::on_sliceSelect_currentIndexChanged(int index)
{
saveData.slice.sliceIndex = index;
}
void TextureSaveDialog::on_gridWidth_valueChanged(double arg1)
{
saveData.slice.sliceGridWidth = (int)arg1;
}
void TextureSaveDialog::on_alphaCol_clicked()
{
QColor col = QColorDialog::getColor(Qt::black, this, tr("Choose background colour"));
if(col.isValid())
{
col = col.toRgb();
saveData.alphaCol = FloatVector(col.redF(), col.greenF(), col.blueF(), 1.0f);
}
}
void TextureSaveDialog::on_alphaMap_currentIndexChanged(int index)
{
saveData.alpha = (AlphaMapping)index;
ui->alphaCol->setEnabled(saveData.alpha == eAlphaMap_BlendToColour);
}
void TextureSaveDialog::on_blackPoint_textEdited(const QString &arg)
{
bool ok = false;
double d = arg.toDouble(&ok);
if(ok)
saveData.comp.blackPoint = d;
}
void TextureSaveDialog::on_whitePoint_textEdited(const QString &arg)
{
bool ok = false;
double d = arg.toDouble(&ok);
if(ok)
saveData.comp.whitePoint = d;
}
void TextureSaveDialog::on_browse_clicked()
{
QString filter = "TODO";
QString *selectedFilter = NULL;
QString filename =
RDDialog::getSaveFileName(this, tr("Save Texture As"), "", filter, selectedFilter);
QFileInfo checkFile(filename);
if(filename != "")
{
ui->filename->setText(filename);
SetFiletypeFromFilename();
}
}
void TextureSaveDialog::on_filename_textEdited(const QString &arg1)
{
}
void TextureSaveDialog::on_saveCancelButtons_accepted()
{
saveData.alpha = (AlphaMapping)ui->alphaMap->currentIndex();
if(saveData.alpha == eAlphaMap_BlendToCheckerboard)
{
saveData.alphaCol = FloatVector(0.666f, 0.666f, 0.666f, 1.0f);
}
if(ui->exportAllMips->isChecked())
saveData.mip = -1;
else
saveData.mip = (int)ui->mipSelect->currentIndex();
if(ui->resolveSamples->isChecked())
{
saveData.sample.sampleIndex = ~0U;
saveData.sample.mapToArray = false;
}
else if(ui->mapSampleArray->isChecked())
{
saveData.sample.sampleIndex = 0;
saveData.sample.mapToArray = true;
}
else
{
saveData.sample.sampleIndex = (uint)ui->sampleSelect->currentIndex();
saveData.sample.mapToArray = false;
}
if(!ui->exportAllSlices->isChecked())
{
saveData.slice.cubeCruciform = saveData.slice.slicesAsGrid = false;
saveData.slice.sliceGridWidth = 1;
saveData.slice.sliceIndex = (int)ui->sliceSelect->currentIndex();
}
else
{
saveData.slice.sliceIndex = -1;
if(ui->cubeCruciform->isChecked())
{
saveData.slice.cubeCruciform = true;
saveData.slice.slicesAsGrid = false;
saveData.slice.sliceGridWidth = 1;
}
else
{
saveData.slice.cubeCruciform = false;
saveData.slice.slicesAsGrid = true;
saveData.slice.sliceGridWidth = (int)ui->gridWidth->value();
}
}
saveData.destType = (FileType)ui->fileFormat->currentIndex();
saveData.jpegQuality = (int)ui->jpegCompression->value();
bool ok = false;
double d = 0.0;
d = ui->blackPoint->text().toDouble(&ok);
if(ok)
saveData.comp.blackPoint = d;
d = ui->whitePoint->text().toDouble(&ok);
if(ok)
saveData.comp.whitePoint = d;
QFileInfo fi(filename());
QDir dir = fi.dir();
bool valid = dir.makeAbsolute();
if(!valid || !dir.exists())
{
RDDialog::critical(this, tr("Save Texture"),
tr("%1\nPath does not exist.\nCheck the path and try again.").arg(filename()));
return;
}
if(fi.exists())
{
QMessageBox::StandardButton button =
RDDialog::question(this, tr("Confirm Save Texture"),
tr("%1 already exists.\nDo you want to replace it?").arg(fi.fileName()));
if(button != QMessageBox::Yes)
return;
}
// path is valid and either doesn't exist or user confirmed replacement
setResult(1);
accept();
}
void TextureSaveDialog::on_saveCancelButtons_rejected()
{
reject();
}
@@ -0,0 +1,83 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2016 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#pragma once
#include <QDialog>
#include "renderdoc_replay.h"
namespace Ui
{
class TextureSaveDialog;
}
class TextureSaveDialog : public QDialog
{
Q_OBJECT
public:
explicit TextureSaveDialog(const FetchTexture &t, const TextureSave &s, QWidget *parent = 0);
~TextureSaveDialog();
QString filename();
TextureSave config() { return saveData; }
private slots:
void on_fileFormat_currentIndexChanged(int index);
void on_jpegCompression_valueChanged(double arg1);
void on_exportAllMips_toggled(bool checked);
void on_oneMip_toggled(bool checked);
void on_mipSelect_currentIndexChanged(int index);
void on_mapSampleArray_toggled(bool checked);
void on_resolveSamples_toggled(bool checked);
void on_oneSample_toggled(bool checked);
void on_sampleSelect_currentIndexChanged(int index);
void on_exportAllSlices_toggled(bool checked);
void on_oneSlice_toggled(bool checked);
void on_mapSlicesToGrid_toggled(bool checked);
void on_cubeCruciform_toggled(bool checked);
void on_sliceSelect_currentIndexChanged(int index);
void on_gridWidth_valueChanged(double arg1);
void on_alphaCol_clicked();
void on_alphaMap_currentIndexChanged(int index);
void on_blackPoint_textEdited(const QString &arg1);
void on_whitePoint_textEdited(const QString &arg1);
void on_browse_clicked();
void on_filename_textEdited(const QString &arg1);
void on_saveCancelButtons_accepted();
void on_saveCancelButtons_rejected();
private:
Ui::TextureSaveDialog *ui;
void SetFilenameFromFiletype();
void SetFiletypeFromFilename();
FetchTexture tex;
TextureSave saveData;
bool m_Recurse = false;
};
@@ -0,0 +1,385 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TextureSaveDialog</class>
<widget class="QDialog" name="TextureSaveDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>527</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>Save Texture</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<widget class="QGroupBox" name="pathGroup">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Path</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item>
<widget class="QLineEdit" name="filename"/>
</item>
<item>
<widget class="QToolButton" name="browse">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="formatGroup">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>File Format</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="formatLabel">
<property name="text">
<string>File Format:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="fileFormat"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="jpegLabel">
<property name="text">
<string>JPEG Compression:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="jpegCompression">
<property name="decimals">
<number>0</number>
</property>
<property name="value">
<double>100.000000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="mipGroup">
<property name="title">
<string>Mips</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item row="1" column="0">
<widget class="QCheckBox" name="oneMip">
<property name="text">
<string>Select Mip:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="mipSelect"/>
</item>
<item row="0" column="0" colspan="2">
<widget class="QCheckBox" name="exportAllMips">
<property name="text">
<string>Export All Mips</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="sampleGroup">
<property name="title">
<string>MSAA Samples</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item row="0" column="0">
<widget class="QCheckBox" name="mapSampleArray">
<property name="text">
<string>Map Samples as Array Slices</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="resolveSamples">
<property name="text">
<string>Resolve Samples</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="oneSample">
<property name="text">
<string>Select Sample:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="sampleSelect"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="sliceGroup">
<property name="title">
<string>Array/Depth Slices</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item row="0" column="0">
<widget class="QCheckBox" name="exportAllSlices">
<property name="text">
<string>Export All Slices</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="oneSlice">
<property name="text">
<string>Select Slice:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="sliceSelect"/>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="mapSlicesToGrid">
<property name="text">
<string>Show Slices as Grid. Grid Width:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="gridWidth">
<property name="decimals">
<number>0</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="cubeCruciform">
<property name="text">
<string>Show Cubemap as Cross</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="alphaGroup">
<property name="title">
<string>Alpha Handling</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item>
<layout class="QHBoxLayout" name="alphaLayout1">
<item>
<widget class="QLabel" name="alphaLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Alpha mapping:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="alphaMap">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>2</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="alphaCol">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Background Colour</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="alphaLayout2">
<item>
<widget class="QLabel" name="blackLabel">
<property name="text">
<string>Black Point:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="blackPoint"/>
</item>
<item>
<widget class="QLabel" name="whiteLabel">
<property name="text">
<string>White Point:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="whitePoint"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="saveCancelButtons">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
</property>
<property name="centerButtons">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+64 -8
View File
@@ -31,19 +31,12 @@
#include <QStyledItemDelegate>
#include "3rdparty/toolwindowmanager/ToolWindowManagerArea.h"
#include "Code/CaptureContext.h"
#include "Dialogs/TextureSaveDialog.h"
#include "Widgets/ResourcePreview.h"
#include "Widgets/TextureGoto.h"
#include "FlowLayout.h"
#include "ui_TextureViewer.h"
struct Formatter
{
static QString Format(float f) { return QString::number(f); }
static QString Format(double d) { return QString::number(d); }
static QString Format(uint32_t u) { return QString::number(u); }
static QString Format(uint16_t u) { return QString::number(u); }
static QString Format(int32_t i) { return QString::number(i); }
};
float area(const QSizeF &s)
{
@@ -3118,6 +3111,69 @@ void TextureViewer::on_viewTexBuffer_clicked()
void TextureViewer::on_saveTex_clicked()
{
FetchTexture *texptr = GetCurrentTexture();
if(!texptr || !m_Output)
return;
TextureSave config = {};
config.id = m_TexDisplay.texid;
config.typeHint = m_TexDisplay.typeHint;
config.slice.sliceIndex = (int)m_TexDisplay.sliceFace;
config.mip = (int)m_TexDisplay.mip;
if(texptr->depth > 1)
config.slice.sliceIndex = (int)m_TexDisplay.sliceFace >> (int)m_TexDisplay.mip;
config.channelExtract = -1;
if(m_TexDisplay.Red && !m_TexDisplay.Green && !m_TexDisplay.Blue && !m_TexDisplay.Alpha)
config.channelExtract = 0;
if(!m_TexDisplay.Red && m_TexDisplay.Green && !m_TexDisplay.Blue && !m_TexDisplay.Alpha)
config.channelExtract = 1;
if(!m_TexDisplay.Red && !m_TexDisplay.Green && m_TexDisplay.Blue && !m_TexDisplay.Alpha)
config.channelExtract = 2;
if(!m_TexDisplay.Red && !m_TexDisplay.Green && !m_TexDisplay.Blue && m_TexDisplay.Alpha)
config.channelExtract = 3;
config.comp.blackPoint = m_TexDisplay.rangemin;
config.comp.whitePoint = m_TexDisplay.rangemax;
config.alphaCol = m_TexDisplay.lightBackgroundColour;
config.alpha = m_TexDisplay.Alpha ? eAlphaMap_BlendToCheckerboard : eAlphaMap_Discard;
if(m_TexDisplay.Alpha && !ui->checkerBack->isChecked())
config.alpha = eAlphaMap_BlendToColour;
if(m_TexDisplay.CustomShader != ResourceId())
{
ResourceId id;
m_Ctx->Renderer()->BlockInvoke(
[this, &id](IReplayRenderer *r) { id = m_Output->GetCustomShaderTexID(); });
if(id != ResourceId())
config.id = id;
}
TextureSaveDialog saveDialog(*texptr, config, this);
int res = RDDialog::show(&saveDialog);
config = saveDialog.config();
if(res)
{
bool ret = false;
QString fn = saveDialog.filename();
m_Ctx->Renderer()->BlockInvoke([this, &ret, config, fn](IReplayRenderer *r) {
ret = r->SaveTexture(config, fn.toUtf8().data());
});
if(!ret)
{
RDDialog::critical(
NULL, tr("Error saving texture"),
tr("Error saving texture %1.\n\nCheck diagnostic log in Help menu for more details.").arg(fn));
}
}
}
void TextureViewer::on_texListShow_clicked()
+6 -3
View File
@@ -100,7 +100,8 @@ SOURCES += 3rdparty/toolwindowmanager/ToolWindowManager.cpp \
Widgets/ResourcePreview.cpp \
Widgets/ThumbnailStrip.cpp \
Widgets/TextureGoto.cpp \
Widgets/RangeHistogram.cpp
Widgets/RangeHistogram.cpp \
Windows/Dialogs/TextureSaveDialog.cpp
HEADERS += 3rdparty/toolwindowmanager/ToolWindowManager.h \
3rdparty/toolwindowmanager/ToolWindowManagerArea.h \
@@ -122,14 +123,16 @@ HEADERS += 3rdparty/toolwindowmanager/ToolWindowManager.h \
Widgets/ResourcePreview.h \
Widgets/ThumbnailStrip.h \
Widgets/TextureGoto.h \
Widgets/RangeHistogram.h
Widgets/RangeHistogram.h \
Windows/Dialogs/TextureSaveDialog.h
FORMS += Windows/Dialogs/AboutDialog.ui \
Windows/MainWindow.ui \
Windows/EventBrowser.ui \
Windows/TextureViewer.ui \
Widgets/ResourcePreview.ui \
Widgets/ThumbnailStrip.ui
Widgets/ThumbnailStrip.ui \
Windows/Dialogs/TextureSaveDialog.ui
RESOURCES += \
resources.qrc
+5
View File
@@ -290,6 +290,7 @@
<ClCompile Include="generated\moc_RDListView.cpp" />
<ClCompile Include="generated\moc_ResourcePreview.cpp" />
<ClCompile Include="generated\moc_TextureGoto.cpp" />
<ClCompile Include="generated\moc_TextureSaveDialog.cpp" />
<ClCompile Include="generated\moc_TextureViewer.cpp" />
<ClCompile Include="generated\moc_ThumbnailStrip.cpp" />
<ClCompile Include="generated\moc_ToolWindowManager.cpp" />
@@ -306,6 +307,7 @@
<ClCompile Include="Code\CaptureContext.cpp" />
<ClCompile Include="Widgets\CustomPaintWidget.cpp" />
<ClCompile Include="Windows\Dialogs\AboutDialog.cpp" />
<ClCompile Include="Windows\Dialogs\TextureSaveDialog.cpp" />
<ClCompile Include="Windows\EventBrowser.cpp" />
<ClCompile Include="3rdparty\flowlayout\FlowLayout.cpp">
<WarningLevel>Level3</WarningLevel>
@@ -332,6 +334,7 @@
<ClInclude Include="generated\ui_EventBrowser.h" />
<ClInclude Include="generated\ui_MainWindow.h" />
<ClInclude Include="generated\ui_ResourcePreview.h" />
<ClInclude Include="generated\ui_TextureSaveDialog.h" />
<ClInclude Include="generated\ui_TextureViewer.h" />
<ClInclude Include="generated\ui_ThumbnailStrip.h" />
<ClInclude Include="Widgets\RangeHistogram.h" />
@@ -344,6 +347,7 @@
<ClInclude Include="Code\CaptureContext.h" />
<ClInclude Include="Widgets\CustomPaintWidget.h" />
<ClInclude Include="Windows\Dialogs\AboutDialog.h" />
<ClInclude Include="Windows\Dialogs\TextureSaveDialog.h" />
<ClInclude Include="Windows\EventBrowser.h" />
<ClInclude Include="3rdparty\flowlayout\FlowLayout.h" />
<ClInclude Include="Widgets\Extended\RDLineEdit.h" />
@@ -358,6 +362,7 @@
<None Include="Widgets\ResourcePreview.ui" />
<None Include="Widgets\ThumbnailStrip.ui" />
<None Include="Windows\Dialogs\AboutDialog.ui" />
<None Include="Windows\Dialogs\TextureSaveDialog.ui" />
<None Include="Windows\EventBrowser.ui" />
<None Include="Windows\MainWindow.ui" />
<None Include="Windows\TextureViewer.ui" />
@@ -163,6 +163,12 @@
<ClCompile Include="Windows\Dialogs\AboutDialog.cpp">
<Filter>Windows\Dialogs</Filter>
</ClCompile>
<ClCompile Include="Windows\Dialogs\TextureSaveDialog.cpp">
<Filter>Windows\Dialogs</Filter>
</ClCompile>
<ClCompile Include="generated\moc_TextureSaveDialog.cpp">
<Filter>Generated Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="3rdparty\flowlayout\FlowLayout.h">
@@ -234,6 +240,12 @@
<ClInclude Include="Windows\Dialogs\AboutDialog.h">
<Filter>Windows\Dialogs</Filter>
</ClInclude>
<ClInclude Include="Windows\Dialogs\TextureSaveDialog.h">
<Filter>Windows\Dialogs</Filter>
</ClInclude>
<ClInclude Include="generated\ui_TextureSaveDialog.h">
<Filter>Generated Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="resources.qrc">
@@ -432,6 +444,12 @@
<None Include="Widgets\ThumbnailStrip.ui">
<Filter>Widgets</Filter>
</None>
<None Include="Windows\Dialogs\AboutDialog.ui">
<Filter>Windows\Dialogs</Filter>
</None>
<None Include="Windows\Dialogs\TextureSaveDialog.ui">
<Filter>Windows\Dialogs</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ClInclude Include="generated\ui_AboutDialog.h">
+2
View File
@@ -166,8 +166,10 @@ struct IReplayOutput
virtual bool GetHistogram(float minval, float maxval, bool channels[4],
rdctype::array<uint32_t> *histogram) = 0;
virtual ResourceId GetCustomShaderTexID() = 0;
virtual bool PickPixel(ResourceId texID, bool customShader, uint32_t x, uint32_t y,
uint32_t sliceFace, uint32_t mip, uint32_t sample, PixelValue *val) = 0;
virtual uint32_t PickVertex(uint32_t eventID, uint32_t x, uint32_t y) = 0;
};
#endif