From 78993cca4d1a9d2c9723c98a59098f43f2cd7315 Mon Sep 17 00:00:00 2001 From: squaresweet Date: Sat, 22 Nov 2025 22:00:36 +0300 Subject: [PATCH] hw1-fin --- src/App/CMakeLists.txt | 4 +- src/App/Shaders/diffuse.fs | 14 ---- src/App/Shaders/diffuse.vs | 16 ----- src/App/Shaders/fractal.fs | 34 +++++++++ src/App/Shaders/fractal.vs | 8 +++ src/App/Window.cpp | 140 +++++++++++++++++++++++++------------ src/App/Window.h | 21 ++++-- src/App/resources.qrc | 4 +- 8 files changed, 157 insertions(+), 84 deletions(-) delete mode 100644 src/App/Shaders/diffuse.fs delete mode 100644 src/App/Shaders/diffuse.vs create mode 100644 src/App/Shaders/fractal.fs create mode 100644 src/App/Shaders/fractal.vs diff --git a/src/App/CMakeLists.txt b/src/App/CMakeLists.txt index 3fed965..6c978e1 100644 --- a/src/App/CMakeLists.txt +++ b/src/App/CMakeLists.txt @@ -3,8 +3,8 @@ set(SRCS Window.cpp Window.h - Shaders/diffuse.fs - Shaders/diffuse.vs + Shaders/fractal.fs + Shaders/fractal.vs Textures/voronoi.png resources.qrc diff --git a/src/App/Shaders/diffuse.fs b/src/App/Shaders/diffuse.fs deleted file mode 100644 index 73a05b2..0000000 --- a/src/App/Shaders/diffuse.fs +++ /dev/null @@ -1,14 +0,0 @@ -#version 330 core - -uniform sampler2D tex_2d; - -in vec3 vert_col; -in vec2 vert_tex; - -out vec4 out_col; - -void main() { - vec4 texel = texture(tex_2d, vert_tex); - float greyscale_factor = dot(texel.rgb, vec3(0.21, 0.71, 0.07)); - out_col = vec4(mix(vec3(greyscale_factor), vert_col.rgb, 0.7), 1.0f); -} \ No newline at end of file diff --git a/src/App/Shaders/diffuse.vs b/src/App/Shaders/diffuse.vs deleted file mode 100644 index 0dd0654..0000000 --- a/src/App/Shaders/diffuse.vs +++ /dev/null @@ -1,16 +0,0 @@ -#version 330 core - -layout(location=0) in vec2 pos; -layout(location=1) in vec3 col; -layout(location=2) in vec2 tex; - -uniform mat4 mvp; - -out vec3 vert_col; -out vec2 vert_tex; - -void main() { - vert_col = col; - vert_tex = tex; - gl_Position = mvp * vec4(pos.xy, 0.0, 1.0); -} diff --git a/src/App/Shaders/fractal.fs b/src/App/Shaders/fractal.fs new file mode 100644 index 0000000..0cba77e --- /dev/null +++ b/src/App/Shaders/fractal.fs @@ -0,0 +1,34 @@ +#version 330 core + +out vec4 frag_color; + +uniform vec2 resolution; +uniform vec2 center; +uniform float zoom; +uniform int max_iter; + +void main() +{ + vec2 uv = gl_FragCoord.xy / resolution; + float aspect = resolution.x / resolution.y; + float cx = (uv.x - 0.5) * zoom + center.x; + float cy = (uv.y - 0.5) * (zoom / aspect) + center.y; + + float x = cx; + float y = cy; + int i; + for (i = 0; i < max_iter; ++i) { + float x2 = x*x - y*y + cx; + float y2 = 2.0*x*y + cy; + x = x2; y = y2; + if (x*x + y*y > 4.0) break; + } + + if (i == max_iter) { + frag_color = vec4(0.0, 0.0, 0.0, 1.0); + } else { + float t = float(i) / float(max_iter); + float brightness = pow(t, 0.5); + frag_color = vec4(brightness, brightness * 0.5, brightness * 0.1, 1.0); + } +} \ No newline at end of file diff --git a/src/App/Shaders/fractal.vs b/src/App/Shaders/fractal.vs new file mode 100644 index 0000000..3c54887 --- /dev/null +++ b/src/App/Shaders/fractal.vs @@ -0,0 +1,8 @@ +#version 330 core + +layout(location = 0) in vec2 pos; + +void main() +{ + gl_Position = vec4(pos, 0.0, 1.0); +} \ No newline at end of file diff --git a/src/App/Window.cpp b/src/App/Window.cpp index 5c607c5..06d4a7f 100644 --- a/src/App/Window.cpp +++ b/src/App/Window.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -18,12 +19,16 @@ namespace { -constexpr std::array vertices = { - 0.0f, 0.707f, 1.f, 0.f, 0.f, 0.0f, 0.0f, - -0.5f, -0.5f, 0.f, 1.f, 0.f, 0.5f, 1.0f, - 0.5f, -0.5f, 0.f, 0.f, 1.f, 1.0f, 0.0f, +constexpr std::array vertices = { + -1.f, 1.f, + -1.f, -1.f, + 1.f, 1.f, + 1.f, -1.f +}; +constexpr std::array indices = { + 0, 1, 2, + 2, 1, 3 }; -constexpr std::array indices = {0, 1, 2}; }// namespace @@ -36,8 +41,26 @@ Window::Window() noexcept auto fps = new QLabel(formatFPS(0), this); fps->setStyleSheet("QLabel { color : white; }"); + auto iter_slider = new QSlider(Qt::Horizontal); + iter_slider->setRange(1, 200); + iter_slider->setValue(max_iter_); + + auto iter_label = new QLabel(QString::number(max_iter_), this); + iter_label->setStyleSheet("QLabel { color: white; }"); + + QObject::connect(iter_slider, &QSlider::valueChanged, [this, iter_label](int new_val) { + this->max_iter_ = new_val; + iter_label->setText(QString::number(new_val)); + }); + + auto slider_layout = new QHBoxLayout(); + slider_layout->addWidget(iter_slider, 1); + slider_layout->addWidget(iter_label, 0); + auto layout = new QVBoxLayout(); - layout->addWidget(fps, 1); + layout->addWidget(fps, 0); + layout->addStretch(1); + layout->addLayout(slider_layout); setLayout(layout); @@ -53,7 +76,6 @@ Window::~Window() { // Free resources with context bounded. const auto guard = bindContext(); - texture_.reset(); program_.reset(); } } @@ -62,9 +84,8 @@ void Window::onInit() { // Configure shaders program_ = std::make_unique(this); - program_->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/diffuse.vs"); - program_->addShaderFromSourceFile(QOpenGLShader::Fragment, - ":/Shaders/diffuse.fs"); + program_->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/fractal.vs"); + program_->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/fractal.fs"); program_->link(); // Create VAO object @@ -83,25 +104,16 @@ void Window::onInit() ibo_.setUsagePattern(QOpenGLBuffer::StaticDraw); ibo_.allocate(indices.data(), static_cast(indices.size() * sizeof(GLuint))); - texture_ = std::make_unique(QImage(":/Textures/voronoi.png")); - texture_->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear); - texture_->setWrapMode(QOpenGLTexture::WrapMode::Repeat); - // Bind attributes program_->bind(); program_->enableAttributeArray(0); - program_->setAttributeBuffer(0, GL_FLOAT, 0, 2, static_cast(7 * sizeof(GLfloat))); - - program_->enableAttributeArray(1); - program_->setAttributeBuffer(1, GL_FLOAT, static_cast(2 * sizeof(GLfloat)), 3, - static_cast(7 * sizeof(GLfloat))); + program_->setAttributeBuffer(0, GL_FLOAT, 0, 2, static_cast(2 * sizeof(GLfloat))); - program_->enableAttributeArray(2); - program_->setAttributeBuffer(2, GL_FLOAT, static_cast(5 * sizeof(GLfloat)), 2, - static_cast(7 * sizeof(GLfloat))); - - mvpUniform_ = program_->uniformLocation("mvp"); + loc_center_= program_->uniformLocation("center"); + loc_zoom_ = program_->uniformLocation("zoom"); + loc_resolution_ = program_->uniformLocation("resolution"); + loc_max_iter_ = program_->uniformLocation("max_iter"); // Release all program_->release(); @@ -126,28 +138,20 @@ void Window::onRender() // Clear buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // Calculate MVP matrix - model_.setToIdentity(); - model_.translate(0, 0, -2); - view_.setToIdentity(); - const auto mvp = projection_ * view_ * model_; - // Bind VAO and shader program program_->bind(); vao_.bind(); - // Update uniform value - program_->setUniformValue(mvpUniform_, mvp); - - // Activate texture unit and bind texture - glActiveTexture(GL_TEXTURE0); - texture_->bind(); + // modern uniforms + program_->setUniformValue(loc_zoom_, zoom_); + program_->setUniformValue(loc_center_, center_); + program_->setUniformValue(loc_resolution_, resolution_); + program_->setUniformValue(loc_max_iter_, max_iter_); // Draw - glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr); + glDrawElements(GL_TRIANGLES, static_cast(indices.size()), GL_UNSIGNED_INT, nullptr); // Release VAO and shader program - texture_->release(); vao_.release(); program_->release(); @@ -164,14 +168,60 @@ void Window::onResize(const size_t width, const size_t height) { // Configure viewport glViewport(0, 0, static_cast(width), static_cast(height)); + resolution_.setX(width); + resolution_.setY(height); +} + +void Window::wheelEvent(QWheelEvent *event) { + const float zoom_factor = 0.01; + + float old_zoom = zoom_; + zoom_ *= 1 + event->angleDelta().ry() * zoom_factor; + + QVector2D mouse_pos(event->position().x() / float(resolution_.x()), + 1.0 - event->position().y() / float(resolution_.y())); + + float aspect = resolution_.x() / float(resolution_.y()); + QVector2D delta( + (mouse_pos.x() - 0.5) * old_zoom, + (mouse_pos.y() - 0.5) * (old_zoom / aspect) + ); + + center_ += delta * (1.0 - zoom_ / old_zoom); +} + +void Window::mousePressEvent(QMouseEvent *event) { + if (event->button() == Qt::LeftButton) { + dragging_ = true; + lastMousePos_ = event->pos(); + } +} + +void Window::mouseReleaseEvent(QMouseEvent *event) { + if (event->button() == Qt::LeftButton) { + dragging_ = false; + } +} + +void Window::mouseMoveEvent(QMouseEvent *event) { + if (!dragging_) + return; + + QPoint currentPos = event->pos(); + QPoint deltaPixels = currentPos - lastMousePos_; + lastMousePos_ = currentPos; + + if (resolution_.x() == 0 || resolution_.y() == 0) + return; + + float aspect = resolution_.x() / float(resolution_.y()); + + QVector2D deltaComplex( + -deltaPixels.x() / resolution_.x() * zoom_, + deltaPixels.y() / resolution_.y() * (zoom_ / aspect) + ); - // Configure matrix - const auto aspect = static_cast(width) / static_cast(height); - const auto zNear = 0.1f; - const auto zFar = 100.0f; - const auto fov = 60.0f; - projection_.setToIdentity(); - projection_.perspective(fov, aspect, zNear, zFar); + center_ += deltaComplex; } Window::PerfomanceMetricsGuard::PerfomanceMetricsGuard(std::function callback) diff --git a/src/App/Window.h b/src/App/Window.h index 1102e2f..2b52e83 100644 --- a/src/App/Window.h +++ b/src/App/Window.h @@ -24,6 +24,11 @@ class Window final : public fgl::GLWidget void onRender() override; void onResize(size_t width, size_t height) override; + void wheelEvent(QWheelEvent * event) override; + void mousePressEvent(QMouseEvent * event) override; + void mouseReleaseEvent(QMouseEvent * event) override; + void mouseMoveEvent(QMouseEvent * event) override; + private: class PerfomanceMetricsGuard final { @@ -48,17 +53,23 @@ class Window final : public fgl::GLWidget void updateUI(); private: - GLint mvpUniform_ = -1; + GLint loc_center_= -1; + GLint loc_zoom_ = -1; + GLint loc_resolution_ = -1; + GLint loc_max_iter_ = -1; QOpenGLBuffer vbo_{QOpenGLBuffer::Type::VertexBuffer}; QOpenGLBuffer ibo_{QOpenGLBuffer::Type::IndexBuffer}; QOpenGLVertexArrayObject vao_; - QMatrix4x4 model_; - QMatrix4x4 view_; - QMatrix4x4 projection_; + QVector2D center_ = QVector2D(0., 0.); + QVector2D resolution_; + float zoom_ = 3.5; + int max_iter_ = 100; + + QPoint lastMousePos_; + bool dragging_ = false; - std::unique_ptr texture_; std::unique_ptr program_; QElapsedTimer timer_; diff --git a/src/App/resources.qrc b/src/App/resources.qrc index 41ba765..e0941c2 100644 --- a/src/App/resources.qrc +++ b/src/App/resources.qrc @@ -6,7 +6,7 @@ Textures/voronoi.png - Shaders/diffuse.fs - Shaders/diffuse.vs + Shaders/fractal.fs + Shaders/fractal.vs \ No newline at end of file