added image saving

master
Benjamin Kraft 3 years ago
parent 7bb704d984
commit d054592840
  1. 11
      headers/Mandelbrot.h
  2. 5
      headers/OutputWidget.h
  3. 20
      src/MainWindow.cpp
  4. 22
      src/Mandelbrot.cpp
  5. 76
      src/OutputWidget.cpp

@ -7,18 +7,23 @@
class Mandelbrot : public QObject, protected QOpenGLExtraFunctions { class Mandelbrot : public QObject, protected QOpenGLExtraFunctions {
Q_OBJECT Q_OBJECT
public: public:
void init(); void init(GLuint);
void draw(GLuint, QOpenGLShaderProgram&); void draw();
void setIterations(int); void setIterations(int);
void translateRelative(QVector2D); void translateRelative(QVector2D);
void zoomRelative(int, QVector2D); void zoomRelative(int, QVector2D);
void resizeRelative(QVector2D); void resizeRelative(QVector2D);
bool initShader();
private: private:
int iterations = 0; int iterations = 0;
QVector2D origin {-2, -1}; QVector2D origin {-2, -1};
QVector2D size {2, 2}; QVector2D size {2, 2};
float zoomModifier = 1.05; float zoomModifier = 1.05;
void setShaderValues(QOpenGLShaderProgram&) const;
GLuint vao;
QOpenGLShaderProgram shader;
void setShaderValues();
}; };

@ -13,6 +13,7 @@ class OutputWidget : public QOpenGLWidget, protected QOpenGLExtraFunctions {
public: public:
explicit OutputWidget(QWidget* parent): QOpenGLWidget(parent) {} explicit OutputWidget(QWidget* parent): QOpenGLWidget(parent) {}
Mandelbrot& getMandelbrot() {return mandelbrot;} Mandelbrot& getMandelbrot() {return mandelbrot;}
void saveToImage(const std::function<void(void)>&, const std::function<void(bool)>&);
private: private:
void initializeGL() override; void initializeGL() override;
void paintGL() override; void paintGL() override;
@ -27,11 +28,7 @@ private:
QPoint mousePos; QPoint mousePos;
QSize oldSize {0, 0}; QSize oldSize {0, 0};
void initShader();
static std::vector<QVector2D> genVertices();
GLuint createVAO(); GLuint createVAO();
GLuint vao {};
QOpenGLShaderProgram shader;
Mandelbrot mandelbrot; Mandelbrot mandelbrot;
}; };

@ -2,6 +2,7 @@
#include <QSlider> #include <QSlider>
#include <QLabel> #include <QLabel>
#include <iostream> #include <iostream>
#include <QPushButton>
#include "../headers/MainWindow.h" #include "../headers/MainWindow.h"
MainWindow::MainWindow(): outputWidget(OutputWidget(this)) { MainWindow::MainWindow(): outputWidget(OutputWidget(this)) {
@ -28,10 +29,29 @@ void MainWindow::buildUI() {
}); });
iterationsSlider->setValue(100); iterationsSlider->setValue(100);
auto saveInfo = new QLabel;
auto saveButton = new QPushButton("Save high resolution image");
connect(
saveButton,
&QPushButton::clicked,
this,
[this, saveInfo](){
saveInfo->setText("Receiving image...");
update();
this->outputWidget.saveToImage([saveInfo](){
saveInfo->setText("Saving...");
}, [saveInfo](bool success){
QString result = success ? "Success" : "Failure";
saveInfo->setText(result);
});
});
auto controls = new QGridLayout; auto controls = new QGridLayout;
controls->addWidget(iterationsCaption, 1, 1); controls->addWidget(iterationsCaption, 1, 1);
controls->addWidget(iterationsLabel, 1, 2); controls->addWidget(iterationsLabel, 1, 2);
controls->addWidget(iterationsSlider, 1, 3); controls->addWidget(iterationsSlider, 1, 3);
controls->addWidget(saveInfo, 2, 1, 1, 2);
controls->addWidget(saveButton, 2, 3, 1, 1);
auto lyt = new QVBoxLayout(this); auto lyt = new QVBoxLayout(this);
lyt->addWidget(&outputWidget); lyt->addWidget(&outputWidget);

@ -1,19 +1,31 @@
#include <QImage>
#include <iostream>
#include <QOpenGLWidget>
#include "../headers/Mandelbrot.h" #include "../headers/Mandelbrot.h"
void Mandelbrot::init() { void Mandelbrot::init(GLuint vaoId) {
initializeOpenGLFunctions(); initializeOpenGLFunctions();
vao = vaoId;
} }
void Mandelbrot::draw(GLuint vao, QOpenGLShaderProgram& shader) { void Mandelbrot::draw() {
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
shader.bind(); shader.bind();
setShaderValues(shader); setShaderValues();
glBindVertexArray(vao); glBindVertexArray(vao);
glDrawArrays(GL_QUADS, 0, 4); glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0); glBindVertexArray(0);
} }
void Mandelbrot::setShaderValues(QOpenGLShaderProgram &shader) const { bool Mandelbrot::initShader() {
if (!shader.addShaderFromSourceFile(QOpenGLShader::Vertex, "Vertex.glsl")) return false;
if (!shader.addShaderFromSourceFile(QOpenGLShader::Fragment, "Fragment.glsl")) return false;
if (!shader.link()) return false;
if (!shader.bind()) return false;
return true;
}
void Mandelbrot::setShaderValues() {
shader.setUniformValue("origin", origin); shader.setUniformValue("origin", origin);
shader.setUniformValue("size", size); shader.setUniformValue("size", size);
shader.setUniformValue("iterationCount", iterations); shader.setUniformValue("iterationCount", iterations);

@ -1,5 +1,10 @@
#include <iostream> #include <iostream>
#include <QResource> #include <QResource>
#include <thread>
#include <future>
#include <QOpenGLFramebufferObject>
#include <QFileDialog>
#include <utility>
#include "../headers/OutputWidget.h" #include "../headers/OutputWidget.h"
using std::cout, std::endl; using std::cout, std::endl;
@ -7,19 +12,28 @@ using std::cout, std::endl;
void OutputWidget::initializeGL() { void OutputWidget::initializeGL() {
cout << "Initialize OpenGL" << endl; cout << "Initialize OpenGL" << endl;
initializeOpenGLFunctions(); initializeOpenGLFunctions();
getMandelbrot().init(); getMandelbrot().init(createVAO());
initShader(); if (!getMandelbrot().initShader()) close();
auto format = this->format(); auto format = this->format();
cout << "OpenGL version: " << format.majorVersion() << "." << format.minorVersion() << endl; cout << "OpenGL version: " << format.majorVersion() << "." << format.minorVersion() << endl;
vao = createVAO();
glClearColor(0.5f, 0.5f, 0.5f, 1.0f); glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
} }
void OutputWidget::paintGL() { void OutputWidget::paintGL() {
getMandelbrot().draw(vao, shader); getMandelbrot().draw();
}
std::vector<QVector2D> genVertices() {
return {
{-1, -1},
{1, -1},
{1, 1},
{1, 1},
{-1, 1},
{-1, -1}
};
} }
GLuint OutputWidget::createVAO() { GLuint OutputWidget::createVAO() {
@ -44,23 +58,6 @@ GLuint OutputWidget::createVAO() {
return vaoId; return vaoId;
} }
std::vector<QVector2D> OutputWidget::genVertices() {
return {
{-1, -1},
{1, -1},
{1, 1},
{-1, 1}
};
}
void OutputWidget::initShader() {
if (!shader.addShaderFromSourceFile(QOpenGLShader::Vertex, "Vertex.glsl")) close();
if (!shader.addShaderFromSourceFile(QOpenGLShader::Fragment, "Fragment.glsl")) close();
if (!shader.link()) close();
if (!shader.bind()) close();
}
QVector2D divide(QPoint p, QSize s){ QVector2D divide(QPoint p, QSize s){
return { return {
float(p.x()) / float(s.width()), float(p.x()) / float(s.width()),
@ -113,3 +110,38 @@ void OutputWidget::mouseReleaseEvent(QMouseEvent *e) {
void OutputWidget::keyPressEvent(QKeyEvent *e) { void OutputWidget::keyPressEvent(QKeyEvent *e) {
} }
void OutputWidget::saveToImage(const std::function<void(void)>& receiveCb, const std::function<void(bool)>& saveCb) {
double maxSize = pow(2, 14);
double div = double(width()) / height();
int w, h;
if (div > 1){
w = int(maxSize);
h = int(maxSize / div);
} else {
h = int(maxSize);
w = int(maxSize * div);
}
QOpenGLFramebufferObject fbo(w, h);
fbo.bind();
glViewport(0, 0, w, h);
getMandelbrot().draw();
QOpenGLFramebufferObject::bindDefault();
QImage img = fbo.toImage();
receiveCb();
QString fileName = QFileDialog::getSaveFileName(this, "", "", tr("Images (*.png *.xpm *.jpg)"));
if (fileName.isNull()){
saveCb(false);
return;
}
std::thread job([saveCb](const QImage& img, const QString& fileName) {
saveCb(img.save(fileName));
}, img, fileName);
job.detach();
}

Loading…
Cancel
Save