src/platform/qt/ShaderSelector.cpp (view raw)
1/* Copyright (c) 2013-2015 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "ShaderSelector.h"
7
8#include "Display.h"
9#include "GBAApp.h"
10#include "VFileDevice.h"
11
12#include <QCheckBox>
13#include <QDoubleSpinBox>
14#include <QFormLayout>
15#include <QGridLayout>
16#include <QSpinBox>
17
18extern "C" {
19#include "platform/video-backend.h"
20
21#if !defined(_WIN32) || defined(USE_EPOXY)
22#include "platform/opengl/gles2.h"
23#endif
24}
25
26using namespace QGBA;
27
28ShaderSelector::ShaderSelector(Display* display, QWidget* parent)
29 : QDialog(parent)
30 , m_display(display)
31{
32 m_ui.setupUi(this);
33
34 refreshShaders();
35
36 connect(m_ui.load, SIGNAL(clicked()), this, SLOT(selectShader()));
37 connect(m_ui.unload, SIGNAL(clicked()), this, SLOT(clearShader()));
38}
39
40ShaderSelector::~ShaderSelector() {
41 clear();
42}
43
44void ShaderSelector::clear() {
45 m_ui.shaderName->setText(tr("No shader active"));
46 m_ui.description->clear();
47 m_ui.author->clear();
48
49 while (QWidget* page = m_ui.passes->widget(0)) {
50 m_ui.passes->removeTab(0);
51 delete page;
52 }
53}
54
55void ShaderSelector::selectShader() {
56 QFileDialog *dialog = GBAApp::app()->getOpenFileDialog(nullptr, tr("Load shader"), tr("%1 Shader (%.shader)").arg(projectName));
57 dialog->setFileMode(QFileDialog::Directory);
58 dialog->exec();
59 QStringList names = dialog->selectedFiles();
60 if (names.count() == 1) {
61 loadShader(names[0]);
62 }
63 delete dialog;
64 refreshShaders();
65}
66
67void ShaderSelector::loadShader(const QString& path) {
68 VDir* shader = VFileDevice::openDir(path);
69 if (!shader) {
70 shader = VFileDevice::openArchive(path);
71 }
72 if (!shader) {
73 return;
74 }
75 m_display->setShaders(shader);
76 shader->close(shader);
77 // TODO: Config
78}
79
80void ShaderSelector::clearShader() {
81 m_display->clearShaders();
82 refreshShaders();
83 // TODO: Config
84}
85
86void ShaderSelector::refreshShaders() {
87 clear();
88 m_shaders = m_display->shaders();
89 if (!m_shaders) {
90 return;
91 }
92 if (m_shaders->name) {
93 m_ui.shaderName->setText(m_shaders->name);
94 } else {
95 m_ui.shaderName->setText(tr("No shader loaded"));
96 }
97 if (m_shaders->description) {
98 m_ui.description->setText(m_shaders->description);
99 } else {
100 m_ui.description->clear();
101 }
102 if (m_shaders->author) {
103 m_ui.author->setText(tr("by %1").arg(m_shaders->author));
104 } else {
105 m_ui.author->clear();
106 }
107
108#if !defined(_WIN32) || defined(USE_EPOXY)
109 GBAGLES2Shader* shaders = static_cast<GBAGLES2Shader*>(m_shaders->passes);
110 for (size_t p = 0; p < m_shaders->nPasses; ++p) {
111 QWidget* page = new QWidget;
112 QFormLayout* layout = new QFormLayout;
113 page->setLayout(layout);
114 for (size_t u = 0 ; u < shaders[p].nUniforms; ++u) {
115 QGridLayout* settings = new QGridLayout;
116 GBAGLES2Uniform* uniform = &shaders[p].uniforms[u];
117 switch (uniform->type) {
118 case GL_FLOAT:
119 addUniform(settings, &uniform->value.f, uniform->min.f, uniform->max.f, 0, 0);
120 break;
121 case GL_FLOAT_VEC2:
122 addUniform(settings, &uniform->value.fvec2[0], uniform->min.fvec2[0], uniform->max.fvec2[0], 0, 0);
123 addUniform(settings, &uniform->value.fvec2[1], uniform->min.fvec2[1], uniform->max.fvec2[1], 0, 1);
124 break;
125 case GL_FLOAT_VEC3:
126 addUniform(settings, &uniform->value.fvec3[0], uniform->min.fvec3[0], uniform->max.fvec3[0], 0, 0);
127 addUniform(settings, &uniform->value.fvec3[1], uniform->min.fvec3[1], uniform->max.fvec3[1], 0, 1);
128 addUniform(settings, &uniform->value.fvec3[2], uniform->min.fvec3[2], uniform->max.fvec3[2], 0, 2);
129 break;
130 case GL_FLOAT_VEC4:
131 addUniform(settings, &uniform->value.fvec4[0], uniform->min.fvec4[0], uniform->max.fvec4[0], 0, 0);
132 addUniform(settings, &uniform->value.fvec4[1], uniform->min.fvec4[1], uniform->max.fvec4[1], 0, 1);
133 addUniform(settings, &uniform->value.fvec4[2], uniform->min.fvec4[2], uniform->max.fvec4[2], 0, 2);
134 addUniform(settings, &uniform->value.fvec4[3], uniform->min.fvec4[3], uniform->max.fvec4[3], 0, 3);
135 break;
136 case GL_INT:
137 addUniform(settings, &uniform->value.i, uniform->min.i, uniform->max.i, 0, 0);
138 break;
139 case GL_INT_VEC2:
140 addUniform(settings, &uniform->value.ivec2[0], uniform->min.ivec2[0], uniform->max.ivec2[0], 0, 0);
141 addUniform(settings, &uniform->value.ivec2[1], uniform->min.ivec2[1], uniform->max.ivec2[1], 0, 1);
142 break;
143 case GL_INT_VEC3:
144 addUniform(settings, &uniform->value.ivec3[0], uniform->min.ivec3[0], uniform->max.ivec3[0], 0, 0);
145 addUniform(settings, &uniform->value.ivec3[1], uniform->min.ivec3[1], uniform->max.ivec3[1], 0, 1);
146 addUniform(settings, &uniform->value.ivec3[2], uniform->min.ivec3[2], uniform->max.ivec3[2], 0, 2);
147 break;
148 case GL_INT_VEC4:
149 addUniform(settings, &uniform->value.ivec4[0], uniform->min.ivec4[0], uniform->max.ivec4[0], 0, 0);
150 addUniform(settings, &uniform->value.ivec4[1], uniform->min.ivec4[1], uniform->max.ivec4[1], 0, 1);
151 addUniform(settings, &uniform->value.ivec4[2], uniform->min.ivec4[2], uniform->max.ivec4[2], 0, 2);
152 addUniform(settings, &uniform->value.ivec4[3], uniform->min.ivec4[3], uniform->max.ivec4[3], 0, 3);
153 break;
154 }
155 layout->addRow(shaders[p].uniforms[u].readableName, settings);
156 }
157 m_ui.passes->addTab(page, tr("Pass %1").arg(p + 1));
158 }
159#endif
160}
161
162void ShaderSelector::addUniform(QGridLayout* settings, float* value, float min, float max, int y, int x) {
163 QDoubleSpinBox* f = new QDoubleSpinBox;
164 f->setDecimals(3);
165 if (min < max) {
166 f->setMinimum(min);
167 f->setMaximum(max);
168 }
169 f->setValue(*value);
170 f->setSingleStep(0.001);
171 f->setAccelerated(true);
172 settings->addWidget(f, y, x);
173 connect(f, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [value](double v) {
174 *value = v;
175 // TODO: Config
176 });
177}
178
179void ShaderSelector::addUniform(QGridLayout* settings, int* value, int min, int max, int y, int x) {
180 QSpinBox* i = new QSpinBox;
181 if (min < max) {
182 i->setMinimum(min);
183 i->setMaximum(max);
184 }
185 i->setValue(*value);
186 i->setSingleStep(1);
187 i->setAccelerated(true);
188 settings->addWidget(i, y, x);
189 connect(i, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), [value](int v) {
190 *value = v;
191 // TODO: Config
192 });
193}