all repos — mgba @ a9ae152dd4793064c3159de59cd3bc6b32a8ebee

mGBA Game Boy Advance Emulator

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}