#include #include #include #include #include #include #include #include #include "../headers/OutputWidget.h" #include using std::cout, std::endl; void OutputWidget::initializeGL() { cout << "Initialize OpenGL" << endl; initializeOpenGLFunctions(); getMandelbrot().init(createVAO()); if (!getMandelbrot().initShader()) close(); auto format = this->format(); cout << "OpenGL version: " << format.majorVersion() << "." << format.minorVersion() << endl; glClearColor(0.5f, 0.5f, 0.5f, 1.0f); auto timer = new QTimer(this); timer->setInterval(17); timer->start(); connect(timer, &QTimer::timeout, this, [this](){ this->getMandelbrot().updateAnimation(); update(); }); } void OutputWidget::paintGL() { getMandelbrot().draw(); } std::vector genVertices() { return { {-1, -1}, {1, -1}, {1, 1}, {1, 1}, {-1, 1}, {-1, -1} }; } GLuint OutputWidget::createVAO() { GLuint vboId; glGenBuffers(1, &vboId); glBindBuffer(GL_ARRAY_BUFFER, vboId); auto vertices = genVertices(); size_t size = vertices.size() * sizeof(QVector2D); glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)size, &vertices[0], GL_STATIC_DRAW); GLuint vaoId; glGenVertexArrays(1, &vaoId); glBindVertexArray(vaoId); glBindBuffer(GL_ARRAY_BUFFER, vboId); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(QVector2D), (void*) nullptr); glEnableVertexAttribArray(0); glBindVertexArray(0); return vaoId; } QVector2D divide(QPoint p, QSize s){ return { float(p.x()) / float(s.width()), float(p.y()) / float(s.height()) }; } QVector2D divide(QSize s1, QSize s2){ return divide(QPoint(s1.width(), s1.height()), s2); } void OutputWidget::resizeGL(int w, int h) { QSize newSize = QSize(w, h); if (oldSize == QSize(0, 0)){ oldSize = newSize; return; } QSize diff = oldSize - newSize; QVector2D relative = QVector2D(1, 1) - divide(diff, oldSize); getMandelbrot().resizeRelative(relative); oldSize = newSize; } void OutputWidget::wheelEvent(QWheelEvent *e) { QPoint pos = e->position().toPoint(); int direction = e->angleDelta().y() > 0 ? 1 : -1; QVector2D relativePos = divide(pos, size()); relativePos.setY(1 - relativePos.y()); getMandelbrot().zoomRelative(direction, relativePos); } void OutputWidget::mouseMoveEvent(QMouseEvent *e) { QPoint newMousePos = e->pos(); QPoint diff = newMousePos - mousePos; mousePos = newMousePos; QVector2D relativeDiff = divide(diff, size()); relativeDiff.setY(-relativeDiff.y()); getMandelbrot().translateRelative(relativeDiff); } void OutputWidget::mousePressEvent(QMouseEvent *e) { mousePos = e->pos(); } void OutputWidget::mouseReleaseEvent(QMouseEvent *e) { } void OutputWidget::keyPressEvent(QKeyEvent *e) { } void OutputWidget::saveToImage(const std::function& receiveCb, const std::function& 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(); }