ACMX 2.139.0
Dual-Backend Real-Time GPU Video Synthesis
Loading...
Searching...
No Matches
shaderpass.cpp
Go to the documentation of this file.
1#include "shaderpass.hpp"
2#include "custom_style.hpp"
3#include <QFile>
4#include <QFileDialog>
5#include <QFileInfo>
6#include <QMessageBox>
7#include <QSettings>
8#include <QTextStream>
9#include <algorithm>
10
11ShaderPassDialog::ShaderPassDialog(const QStringList &shaderNames, QWidget *parent) : QDialog(parent) {
12 setWindowTitle("Multi-Pass Shader Settings");
13 setMinimumSize(500, 500);
14 setupUI();
15 loadShaders(shaderNames);
16}
17
19 QVBoxLayout *mainLayout = new QVBoxLayout(this);
20
21 enableCheckBox = new QCheckBox("Enable Multi-Pass Shader Processing", this);
22 mainLayout->addWidget(enableCheckBox);
23
24 QLabel *infoLabel = new QLabel("Multi-pass rendering applies multiple shaders in sequence.\n"
25 "Each shader processes the output of the previous shader.",
26 this);
27 infoLabel->setWordWrap(true);
28 mainLayout->addWidget(infoLabel);
29 QGroupBox *shaderGroup = new QGroupBox("Shader Pass Selection", this);
30 QVBoxLayout *shaderMainLayout = new QVBoxLayout(shaderGroup);
31 QHBoxLayout *searchLayout = new QHBoxLayout();
32 QLabel *searchLabel = new QLabel("Search:", this);
33 searchLineEdit = new QLineEdit(this);
34 searchLineEdit->setPlaceholderText("Type to search shaders...");
35 searchLineEdit->setClearButtonEnabled(true);
36 searchLayout->addWidget(searchLabel);
37 searchLayout->addWidget(searchLineEdit, 1);
38 shaderMainLayout->addLayout(searchLayout);
39
40 QHBoxLayout *comboLayout = new QHBoxLayout();
41 QLabel *availableLabel = new QLabel("Available Shaders:", this);
42 shaderComboBox = new QComboBox(this);
43 shaderComboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
44 shaderComboBox->setMaxVisibleItems(20);
45
46 shaderModel = new QStandardItemModel(this);
47 proxyModel = new QSortFilterProxyModel(this);
48 proxyModel->setSourceModel(shaderModel);
49 proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
50 proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
51 shaderComboBox->setModel(proxyModel);
52
53 comboLayout->addWidget(availableLabel);
54 comboLayout->addWidget(shaderComboBox, 1);
55 shaderMainLayout->addLayout(comboLayout);
56
57 QHBoxLayout *buttonLayout = new QHBoxLayout();
58 addButton = new QPushButton("Add →", this);
59 insertButton = new QPushButton("Insert", this);
60 insertButton->setToolTip("Replace the selected pass with the available shader.");
61 removeButton = new QPushButton("← Remove", this);
62 upButton = new QPushButton("↑ Up", this);
63 downButton = new QPushButton("↓ Down", this);
64 clearButton = new QPushButton("Clear All", this);
65 buttonLayout->addWidget(addButton);
66 buttonLayout->addWidget(insertButton);
67 buttonLayout->addWidget(removeButton);
68 buttonLayout->addWidget(upButton);
69 buttonLayout->addWidget(downButton);
70 buttonLayout->addWidget(clearButton);
71 shaderMainLayout->addLayout(buttonLayout);
72
73 QLabel *selectedLabel = new QLabel("Shader Pass Order (processed in sequence):", this);
74 shaderMainLayout->addWidget(selectedLabel);
75 selectedShadersList = new QListWidget(this);
76 selectedShadersList->setMinimumHeight(200);
77 selectedShadersList->setToolTip("Double-click a shader to open it in the code editor.");
78 shaderMainLayout->addWidget(selectedShadersList);
79
80 QHBoxLayout *fileButtonLayout = new QHBoxLayout();
81 saveButton = new QPushButton("Save List...", this);
82 loadButton = new QPushButton("Load List...", this);
83 fileButtonLayout->addWidget(saveButton);
84 fileButtonLayout->addWidget(loadButton);
85 fileButtonLayout->addStretch();
86 shaderMainLayout->addLayout(fileButtonLayout);
87
88 mainLayout->addWidget(shaderGroup);
89
90 QHBoxLayout *dialogButtonLayout = new QHBoxLayout();
91 okButton = new QPushButton("OK", this);
92 applyButton = new QPushButton("Apply", this);
93 cancelButton = new QPushButton("Cancel", this);
94 dialogButtonLayout->addStretch();
95 dialogButtonLayout->addWidget(okButton);
96 dialogButtonLayout->addWidget(applyButton);
97 dialogButtonLayout->addWidget(cancelButton);
98 mainLayout->addLayout(dialogButtonLayout);
99
100 connect(addButton, &QPushButton::clicked, this, &ShaderPassDialog::addShader);
101 connect(insertButton, &QPushButton::clicked, this, &ShaderPassDialog::insertShader);
102 connect(removeButton, &QPushButton::clicked, this, &ShaderPassDialog::removeShader);
103 connect(upButton, &QPushButton::clicked, this, &ShaderPassDialog::moveUp);
104 connect(downButton, &QPushButton::clicked, this, &ShaderPassDialog::moveDown);
105 connect(clearButton, &QPushButton::clicked, this, &ShaderPassDialog::clearAll);
106 connect(saveButton, &QPushButton::clicked, this, &ShaderPassDialog::saveShaderPass);
107 connect(loadButton, &QPushButton::clicked, this, &ShaderPassDialog::loadShaderPass);
108 connect(applyButton, &QPushButton::clicked, this, &ShaderPassDialog::applyChanges);
109 connect(okButton, &QPushButton::clicked, this, &QDialog::accept);
110 connect(cancelButton, &QPushButton::clicked, this, &QDialog::reject);
111 connect(searchLineEdit, &QLineEdit::textChanged, this, &ShaderPassDialog::filterSearchChanged);
112 connect(selectedShadersList, &QListWidget::currentRowChanged, this, [this](int row) { insertButton->setEnabled(enableCheckBox->isChecked() && row >= 0); });
113 connect(selectedShadersList, &QListWidget::itemDoubleClicked, this, [this](QListWidgetItem *item) {
114 if (item)
115 emit shaderEditRequested(item->text());
116 });
117
118 connect(enableCheckBox, &QCheckBox::toggled, this, [this](bool checked) {
119 shaderComboBox->setEnabled(checked);
120 selectedShadersList->setEnabled(checked);
121 searchLineEdit->setEnabled(checked);
122 addButton->setEnabled(checked);
123 insertButton->setEnabled(checked && selectedShadersList->currentRow() >= 0);
124 removeButton->setEnabled(checked);
125 upButton->setEnabled(checked);
126 downButton->setEnabled(checked);
127 clearButton->setEnabled(checked);
128 saveButton->setEnabled(checked);
129 loadButton->setEnabled(checked);
130 });
131
132 enableCheckBox->setChecked(false);
133 shaderComboBox->setEnabled(false);
134 selectedShadersList->setEnabled(false);
135 searchLineEdit->setEnabled(false);
136 addButton->setEnabled(false);
137 insertButton->setEnabled(false);
138 removeButton->setEnabled(false);
139 upButton->setEnabled(false);
140 downButton->setEnabled(false);
141 clearButton->setEnabled(false);
142 saveButton->setEnabled(false);
143 loadButton->setEnabled(false);
144
146}
147
148void ShaderPassDialog::loadShaders(const QStringList &shaderNames) {
149 QStringList selectedNames = getSelectedShaderNames();
150
151 shaderNamesList.clear();
152 shaderNameToIndex.clear();
153 shaderModel->clear();
154
155 for (int i = 0; i < shaderNames.size(); ++i) {
156 QString name = shaderNames[i];
157 shaderNamesList.append(name);
158 shaderNameToIndex[name] = i;
159 QStandardItem *item = new QStandardItem(name);
160 item->setData(i, Qt::UserRole);
161 shaderModel->appendRow(item);
162 }
163
164 if (!selectedNames.isEmpty()) {
165 setSelectedShaderNames(selectedNames);
166 }
167
168 if (shaderNamesList.isEmpty()) {
169 QMessageBox::warning(this, "Warning", "No shaders loaded. Please load a shader library first.");
170 }
171}
172
173void ShaderPassDialog::filterSearchChanged(const QString &text) {
174 proxyModel->setFilterFixedString(text);
175 if (proxyModel->rowCount() > 0) {
176 shaderComboBox->setCurrentIndex(0);
177 }
178}
179
181 if (shaderComboBox->currentIndex() < 0) {
182 return;
183 }
184
185 QString shaderName = shaderComboBox->currentText();
186 QListWidgetItem *item = new QListWidgetItem(shaderName);
187 if (shaderNameToIndex.contains(shaderName)) {
188 item->setData(Qt::UserRole, shaderNameToIndex[shaderName]);
189 }
190 selectedShadersList->addItem(item);
191}
192
194 const int currentRow = selectedShadersList->currentRow();
195 if (currentRow < 0 || shaderComboBox->currentIndex() < 0) {
196 return;
197 }
198
199 const QString shaderName = shaderComboBox->currentText();
200 QListWidgetItem *item = selectedShadersList->item(currentRow);
201 item->setText(shaderName);
202 if (shaderNameToIndex.contains(shaderName)) {
203 item->setData(Qt::UserRole, shaderNameToIndex[shaderName]);
204 }
205}
206
208 QListWidgetItem *item = selectedShadersList->currentItem();
209 if (item) {
210 delete selectedShadersList->takeItem(selectedShadersList->row(item));
211 }
212}
213
215 int currentRow = selectedShadersList->currentRow();
216 if (currentRow > 0) {
217 QListWidgetItem *item = selectedShadersList->takeItem(currentRow);
218 selectedShadersList->insertItem(currentRow - 1, item);
219 selectedShadersList->setCurrentRow(currentRow - 1);
220 }
221}
222
224 int currentRow = selectedShadersList->currentRow();
225 if (currentRow >= 0 && currentRow < selectedShadersList->count() - 1) {
226 QListWidgetItem *item = selectedShadersList->takeItem(currentRow);
227 selectedShadersList->insertItem(currentRow + 1, item);
228 selectedShadersList->setCurrentRow(currentRow + 1);
229 }
230}
231
233
234bool ShaderPassDialog::isShaderPassEnabled() const { return enableCheckBox->isChecked() && selectedShadersList->count() > 0; }
235
237 QStringList indices;
238 for (int i = 0; i < selectedShadersList->count(); ++i) {
239 QListWidgetItem *item = selectedShadersList->item(i);
240 int idx = item->data(Qt::UserRole).toInt();
241 indices.append(QString::number(idx));
242 }
243 return indices;
244}
245
247 QStringList indices = getSelectedShaderIndices();
248 return indices.join(",");
249}
250
251void ShaderPassDialog::setEnabled(bool enabled) { enableCheckBox->setChecked(enabled); }
252
253void ShaderPassDialog::setSelectedIndices(const QStringList &indices) {
254 selectedShadersList->clear();
255 for (const QString &idxStr : indices) {
256 bool ok;
257 int idx = idxStr.toInt(&ok);
258 if (ok && idx >= 0 && idx < shaderNamesList.size()) {
259 QString name = shaderNamesList[idx];
260 QListWidgetItem *item = new QListWidgetItem(name);
261 item->setData(Qt::UserRole, idx);
262 selectedShadersList->addItem(item);
263 }
264 }
265}
266
268 QStringList names;
269 for (int i = 0; i < selectedShadersList->count(); ++i) {
270 QListWidgetItem *item = selectedShadersList->item(i);
271 names.append(item->text());
272 }
273 return names;
274}
275
276void ShaderPassDialog::setSelectedShaderNames(const QStringList &names) {
277 selectedShadersList->clear();
278 for (const QString &name : names) {
279 if (shaderNameToIndex.contains(name)) {
280 int idx = shaderNameToIndex[name];
281 QListWidgetItem *item = new QListWidgetItem(name);
282 item->setData(Qt::UserRole, idx);
283 selectedShadersList->addItem(item);
284 }
285 }
286}
287
288void ShaderPassDialog::updateShaderList(const QStringList &shaderNames) { loadShaders(shaderNames); }
289
291
293 if (selectedShadersList->count() == 0) {
294 QMessageBox::information(this, "Empty List", "Add shaders to the pass list before saving.");
295 return;
296 }
297
298 QSettings appSettings("LostSideDead");
299 QString lastDir = appSettings.value("lastShaderPassDir", "").toString();
300 QString filePath = QFileDialog::getSaveFileName(this, "Save Shader Pass List", lastDir, "Text Files (*.txt);;All Files (*)");
301 if (filePath.isEmpty())
302 return;
303
304 appSettings.setValue("lastShaderPassDir", QFileInfo(filePath).absolutePath());
305
306 QFile file(filePath);
307 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
308 QMessageBox::critical(this, "Error", "Could not save file: " + filePath);
309 return;
310 }
311
312 QTextStream out(&file);
313 for (int i = 0; i < selectedShadersList->count(); ++i) {
314 out << selectedShadersList->item(i)->text() << "\n";
315 }
316 file.close();
317 QMessageBox::information(this, "Saved", "Shader pass list saved to: " + filePath);
318}
319
321 QSettings appSettings("LostSideDead");
322 QString lastDir = appSettings.value("lastShaderPassDir", "").toString();
323 QString filePath = QFileDialog::getOpenFileName(this, "Load Shader Pass List", lastDir, "Text Files (*.txt);;All Files (*)");
324 if (filePath.isEmpty())
325 return;
326
327 appSettings.setValue("lastShaderPassDir", QFileInfo(filePath).absolutePath());
328
329 QFile file(filePath);
330 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
331 QMessageBox::critical(this, "Error", "Could not open file: " + filePath);
332 return;
333 }
334
335 selectedShadersList->clear();
336 QTextStream in(&file);
337 int loadedCount = 0;
338 int skippedCount = 0;
339 while (!in.atEnd()) {
340 QString line = in.readLine().trimmed();
341 if (line.isEmpty())
342 continue;
343 if (shaderNameToIndex.contains(line)) {
344 QListWidgetItem *item = new QListWidgetItem(line);
345 item->setData(Qt::UserRole, shaderNameToIndex[line]);
346 selectedShadersList->addItem(item);
347 ++loadedCount;
348 } else {
349 ++skippedCount;
350 }
351 }
352 file.close();
353
354 QString msg = "Loaded " + QString::number(loadedCount) + " shader(s).";
355 if (skippedCount > 0)
356 msg += "\n" + QString::number(skippedCount) + " shader(s) not found and skipped.";
357 QMessageBox::information(this, "Shader Pass List Loaded", msg);
358}
void setSelectedIndices(const QStringList &indices)
void shaderEditRequested(const QString &shaderName)
Request that a shader in the pass list be opened for editing.
QCheckBox * enableCheckBox
void loadShaders(const QStringList &shaderNames)
QStringList getSelectedShaderNames() const
Return selected shader names in execution order.
QPushButton * insertButton
QLineEdit * searchLineEdit
QPushButton * saveButton
QString getShaderPassArgument() const
Build CLI argument payload for selected shader passes.
bool isShaderPassEnabled() const
Return whether shader-pass mode is enabled.
void setEnabled(bool enabled)
QSortFilterProxyModel * proxyModel
QPushButton * removeButton
void updateShaderList(const QStringList &shaderNames)
QPushButton * cancelButton
QPushButton * upButton
QPushButton * applyButton
void setSelectedShaderNames(const QStringList &names)
QPushButton * clearButton
QStringList getSelectedShaderIndices() const
Return selected pass indices corresponding to available shader list.
QStandardItemModel * shaderModel
QListWidget * selectedShadersList
QPushButton * downButton
void settingsApplied(bool enabled, const QStringList &selectedShaderNames)
QPushButton * okButton
void filterSearchChanged(const QString &text)
ShaderPassDialog(const QStringList &shaderNames, QWidget *parent=nullptr)
QStringList shaderNamesList
QPushButton * loadButton
QMap< QString, int > shaderNameToIndex
QComboBox * shaderComboBox
QPushButton * addButton
void applyCustomStyleIfEnabled(QWidget *widget)
Dialog for configuring ordered multi-pass shader execution.