From 81f5f3fe7b4b49428d002fa75f5b11f3e72dddb7 Mon Sep 17 00:00:00 2001 From: Benjamin Kraft Date: Wed, 13 Sep 2023 01:13:55 +0200 Subject: [PATCH] add basics, new signal for changed pendulums, added shaders --- CMakeLists.txt | 2 +- shaders/fragment.glsl | 9 +++++ shaders/shaders.qrc | 6 +++ shaders/vertex.glsl | 11 ++++++ src/GLWidget.cpp | 86 +++++++++++++++++++++++++++++++++++++++---- src/GLWidget.h | 17 ++++++--- src/MainWindow.cpp | 3 ++ src/Pendulum.h | 3 +- src/Simulation.cpp | 13 ++++++- src/Simulation.h | 5 ++- 10 files changed, 139 insertions(+), 16 deletions(-) create mode 100644 shaders/fragment.glsl create mode 100644 shaders/shaders.qrc create mode 100644 shaders/vertex.glsl diff --git a/CMakeLists.txt b/CMakeLists.txt index f393b6a..c387957 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,6 @@ find_package(Qt6 COMPONENTS OpenGLWidgets REQUIRED) find_package(OpenMP REQUIRED) file(GLOB_RECURSE SOURCE_FILES src/**.cpp) -add_executable(Pendulum WIN32 ${SOURCE_FILES} icons/icons.qrc) +add_executable(Pendulum WIN32 ${SOURCE_FILES} icons/icons.qrc shaders/shaders.qrc) target_link_libraries(Pendulum Qt6::OpenGLWidgets OpenMP::OpenMP_CXX) diff --git a/shaders/fragment.glsl b/shaders/fragment.glsl new file mode 100644 index 0000000..6daa09f --- /dev/null +++ b/shaders/fragment.glsl @@ -0,0 +1,9 @@ +#version 330 core + +out vec4 FragColor; + +in vec3 color; + +void main() { + FragColor = vec4(color, 1); +} diff --git a/shaders/shaders.qrc b/shaders/shaders.qrc new file mode 100644 index 0000000..65aede6 --- /dev/null +++ b/shaders/shaders.qrc @@ -0,0 +1,6 @@ + + + vertex.glsl + fragment.glsl + + \ No newline at end of file diff --git a/shaders/vertex.glsl b/shaders/vertex.glsl new file mode 100644 index 0000000..7cc789b --- /dev/null +++ b/shaders/vertex.glsl @@ -0,0 +1,11 @@ +#version 330 core + +layout (location = 0) in vec2 vPos; +layout (location = 1) in vec3 vColor; + +out vec3 color; + +void main() { + gl_Position = vec4(vPos, 0.0, 1.0); + color = vColor; +} diff --git a/src/GLWidget.cpp b/src/GLWidget.cpp index e83081e..3d3a80f 100644 --- a/src/GLWidget.cpp +++ b/src/GLWidget.cpp @@ -7,29 +7,93 @@ #include #include #include "FPS.h" +#include GLWidget::GLWidget(Simulation * simulation) : simulation(simulation) { startTimer(1000 / 144); fps = new FPS; fps->setUpdateInterval(500); + connect(simulation, &Simulation::pendulaChanged, this, &GLWidget::initGPUMemory); } -void GLWidget::paintEvent(QPaintEvent *e) { - fps->newFrame(); - QString fpsString = "FPS: " + QString::fromStdString(std::to_string(fps->current)); +void GLWidget::initializeGL() { + initializeOpenGLFunctions(); + glEnable(GL_PRIMITIVE_RESTART); + glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); + glClearColor(.15, .15, .15, 1); + program = new QOpenGLShaderProgram; + program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/vertex.glsl"); + program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/fragment.glsl"); + program->link(); + program->bind(); + + glGenVertexArrays(1, &VAO); + glBindVertexArray(VAO); + + float vertices[] = { + -0.5, -0.5, + 0.5, -0.5, + 0.5, 0.5, + -0.5, 0.5 + }; + + float colors[] = { + 1, 0, 0, + 0, 1, 0, + 0, 0, 1, + 1, 1, 0 + }; + + GLushort indices[] = { + 0, 1, 0xffff, 2, 3 + }; + + glGenBuffers(1, &positionVBO); + glBindBuffer(GL_ARRAY_BUFFER, positionVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr); + glEnableVertexAttribArray(0); + + GLuint colorVBO; + glGenBuffers(1, &colorVBO); + glBindBuffer(GL_ARRAY_BUFFER, colorVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr); + glEnableVertexAttribArray(1); + + GLuint ebo; + glGenBuffers(1, &ebo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); + + glBindVertexArray(0); +} +void GLWidget::paintGL() { auto p = new QPainter(this); p->setRenderHint(QPainter::Antialiasing); - p->fillRect(e->rect(), QColor(30, 30, 30)); + p->beginNativePainting(); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glViewport(0, 0, QWidget::width(), QWidget::height()); + + program->bind(); + glBindVertexArray(VAO); + glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_SHORT, nullptr); + simulation->draw(nullptr, std::min(width(), height())); + glBindVertexArray(0); + + p->endNativePainting(); + p->setPen(Qt::white); auto font = p->font(); font.setPixelSize(20); p->setFont(font); - p->drawText(0, 0, 400, 400, Qt::AlignTop | Qt::AlignLeft, fpsString); - p->translate(e->rect().center()); - simulation->draw(p, std::min(width(), height())); + fps->newFrame(); + QString fpsString = "FPS: " + QString::fromStdString(std::to_string(fps->current)); + p->drawText(0, 0, 100, 100, Qt::AlignTop | Qt::AlignLeft, fpsString); p->end(); } @@ -46,4 +110,12 @@ bool GLWidget::AnyDialogOpen() { return false; } +void GLWidget::initGPUMemory(const std::vector &addPendula) { + glBindBuffer(GL_ARRAY_BUFFER, positionVBO); + auto positions = (GLfloat*) glMapBufferRange(GL_ARRAY_BUFFER, 0, 2 * 3 * sizeof(float), GL_MAP_WRITE_BIT); + + glUnmapBuffer(GL_ARRAY_BUFFER); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + diff --git a/src/GLWidget.h b/src/GLWidget.h index c740c18..6813123 100644 --- a/src/GLWidget.h +++ b/src/GLWidget.h @@ -1,18 +1,25 @@ #include -#include - - +#include +class Pendulum; class Simulation; class FPS; +class QOpenGLShaderProgram; -class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions { +class GLWidget : public QOpenGLWidget, protected QOpenGLExtraFunctions { public: explicit GLWidget(Simulation *); protected: - void paintEvent(QPaintEvent* e) override; void timerEvent(QTimerEvent* e) override; + void initializeGL() override; + void paintGL() override; +private slots: + void initGPUMemory(const std::vector &addPendula); private: + QOpenGLShaderProgram * program; + GLuint VAO; + GLuint positionVBO; + GLsizei indexCount; Simulation * simulation; FPS * fps; static bool AnyDialogOpen(); diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 3f6caf6..b4da9f0 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -30,6 +30,9 @@ MainWindow::MainWindow() { resetLengths(); buildUI(); + + normalizeLengths(); + add(); } void MainWindow::buildUI() { diff --git a/src/Pendulum.h b/src/Pendulum.h index f748371..c6159af 100644 --- a/src/Pendulum.h +++ b/src/Pendulum.h @@ -1,3 +1,5 @@ +#pragma once + #include #include #include @@ -13,7 +15,6 @@ public: void draw(QPainter*, double) const; void update(double, double); - private: std::vector X, V; std::vector M, L; diff --git a/src/Simulation.cpp b/src/Simulation.cpp index f2f080e..9c3c727 100644 --- a/src/Simulation.cpp +++ b/src/Simulation.cpp @@ -1,5 +1,4 @@ #include "Simulation.h" -#include "Pendulum.h" #include #include #include @@ -19,8 +18,12 @@ void Simulation::draw(QPainter *p, int screenSize) { double scale = screenSize * 0.95 / size; + + + /* for (const auto pendulum : pendula) pendulum->draw(p, scale); + */ pendulaMutex.unlock(); } @@ -52,10 +55,18 @@ void Simulation::clearPendula() { pendula.shrink_to_fit(); pendulaMutex.unlock(); + + emit pendulaChanged(pendula); } void Simulation::addPendula(const std::vector &add) { + pendulaMutex.lock(); + for (auto p : add) pendula.push_back(p); + + pendulaMutex.unlock(); + + emit pendulaChanged(pendula); } diff --git a/src/Simulation.h b/src/Simulation.h index 2f80c4e..8042fb7 100644 --- a/src/Simulation.h +++ b/src/Simulation.h @@ -3,14 +3,15 @@ #include #include #include +#include "Pendulum.h" using namespace std::chrono; -class Pendulum; class QPainter; class QTimer; class Simulation : public QObject { + Q_OBJECT public: explicit Simulation(); @@ -23,6 +24,8 @@ public: bool isPlaying = false; void draw(QPainter*, int); +signals: + void pendulaChanged(const std::vector &newPendula); public slots: void clearPendula(); void addPendula(const std::vector &add);