From 49dc19b39fe0f1b9142c043ac08e7e8c7cb76943 Mon Sep 17 00:00:00 2001 From: Benjamin Kraft Date: Wed, 13 Sep 2023 21:31:25 +0200 Subject: [PATCH] drawing done with opengl, without mass points --- shaders/vertex.glsl | 4 +- src/GLWidget.cpp | 148 ++++++++++++++++++++++++++++++-------------- src/GLWidget.h | 14 ++++- src/MainWindow.cpp | 4 +- src/Pendulum.h | 2 + src/Simulation.cpp | 36 ++++------- src/Simulation.h | 6 +- 7 files changed, 136 insertions(+), 78 deletions(-) diff --git a/shaders/vertex.glsl b/shaders/vertex.glsl index 7cc789b..5d3df08 100644 --- a/shaders/vertex.glsl +++ b/shaders/vertex.glsl @@ -3,9 +3,11 @@ layout (location = 0) in vec2 vPos; layout (location = 1) in vec3 vColor; +uniform mat2 VP; + out vec3 color; void main() { - gl_Position = vec4(vPos, 0.0, 1.0); + gl_Position = vec4(VP * vPos, 0.0, 1.0); color = vColor; } diff --git a/src/GLWidget.cpp b/src/GLWidget.cpp index 3d3a80f..f0c0ddd 100644 --- a/src/GLWidget.cpp +++ b/src/GLWidget.cpp @@ -13,60 +13,22 @@ GLWidget::GLWidget(Simulation * simulation) : simulation(simulation) { startTimer(1000 / 144); fps = new FPS; fps->setUpdateInterval(500); - connect(simulation, &Simulation::pendulaChanged, this, &GLWidget::initGPUMemory); + connect(simulation, &Simulation::layoutChanged, this, &GLWidget::initGPUMemory); + connect(simulation, &Simulation::positionChanged, this, &GLWidget::changePosition); } 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); + glGenBuffers(1, &EBO); } void GLWidget::paintGL() { @@ -74,13 +36,17 @@ void GLWidget::paintGL() { p->setRenderHint(QPainter::Antialiasing); p->beginNativePainting(); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glEnable(GL_PRIMITIVE_RESTART); + glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); + glClearColor(.15, .15, .15, 1); + + glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, QWidget::width(), QWidget::height()); program->bind(); + program->setUniformValue("VP", VP); glBindVertexArray(VAO); - glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_SHORT, nullptr); - simulation->draw(nullptr, std::min(width(), height())); + glDrawElements(GL_LINE_STRIP, indexCount, GL_UNSIGNED_INT, nullptr); glBindVertexArray(0); p->endNativePainting(); @@ -110,12 +76,100 @@ bool GLWidget::AnyDialogOpen() { return false; } -void GLWidget::initGPUMemory(const std::vector &addPendula) { +void GLWidget::initGPUMemory(const std::vector *pendula) { + + std::vector positions; + std::vector colors; + std::vector massRadii; + std::vector indices; + + GLuint index = 0; + for (const auto p : *pendula){ + + // Origin point + positions.push_back(0); + positions.push_back(0); + + colors.resize(colors.size() + 3); + float * red = &colors.back() - 2; + p->color.getRgbF(red, red + 1, red + 2); + + massRadii.push_back(0); + + indices.push_back(index++); + + // All other points + for (int segment = 0; segment < p->M.size(); segment++){ + Vector pos = p->X[segment]; + positions.push_back(float(pos.x)); + positions.push_back(float(pos.y)); + + colors.resize(colors.size() + 3); + red = &colors.back() - 2; + p->color.getRgbF(red, red + 1, red + 2); + + massRadii.push_back(float(p->M[segment])); + + indices.push_back(index++); + } + + // Primitive Restart + indices.push_back(0xFFFFFFFF); + } + + indexCount = GLsizei(indices.size()); + positionCount = GLsizei(positions.size()); + + glBindVertexArray(VAO); + glBindBuffer(GL_ARRAY_BUFFER, positionVBO); - auto positions = (GLfloat*) glMapBufferRange(GL_ARRAY_BUFFER, 0, 2 * 3 * sizeof(float), GL_MAP_WRITE_BIT); + glBufferData(GL_ARRAY_BUFFER, GLsizeiptr(positions.size() * sizeof(float)), positions.data(), GL_DYNAMIC_DRAW); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr); + glEnableVertexAttribArray(0); + + glBindBuffer(GL_ARRAY_BUFFER, colorVBO); + glBufferData(GL_ARRAY_BUFFER, GLsizeiptr(colors.size() * sizeof(float)), colors.data(), GL_STATIC_DRAW); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr); + glEnableVertexAttribArray(1); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, GLsizeiptr(indices.size() * sizeof(GLuint)), indices.data(), GL_STATIC_DRAW); + + glBindVertexArray(0); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + simulation->pendulaMutex.unlock(); +} + +void GLWidget::changePosition(const std::vector *pendula) { + glBindBuffer(GL_ARRAY_BUFFER, positionVBO); + auto positions = (GLfloat*) glMapBufferRange(GL_ARRAY_BUFFER, 0, GLsizeiptr(positionCount * sizeof(float)), GL_MAP_WRITE_BIT); + if (positions){ + size_t index = 0; + for (const auto p : *pendula){ + index += 2; + for (auto x : p->X){ + positions[index++] = float(x.x); + positions[index++] = float(x.y); + } + } + } + simulation->pendulaMutex.unlock(); glUnmapBuffer(GL_ARRAY_BUFFER); glBindBuffer(GL_ARRAY_BUFFER, 0); } +void GLWidget::resizeGL(int w, int h) { + float m = std::min(float(w), float(h)); + float scale = 1 / (float(simulation->size) / 2) * 0.9f; + + VP.setToIdentity(); + VP(0, 0) = 1 / float(w); + VP(1, 1) = -1 / float(h); + VP *= m * scale; +} + + diff --git a/src/GLWidget.h b/src/GLWidget.h index 6813123..f0f142d 100644 --- a/src/GLWidget.h +++ b/src/GLWidget.h @@ -1,5 +1,8 @@ +#pragma once + #include #include +#include class Pendulum; class Simulation; @@ -13,13 +16,20 @@ protected: void timerEvent(QTimerEvent* e) override; void initializeGL() override; void paintGL() override; + void resizeGL(int w, int h) override; private slots: - void initGPUMemory(const std::vector &addPendula); + void initGPUMemory(const std::vector *pendula); + void changePosition(const std::vector *pendula); private: QOpenGLShaderProgram * program; GLuint VAO; GLuint positionVBO; - GLsizei indexCount; + GLuint colorVBO; + GLuint EBO; + GLsizei indexCount = 0; + GLsizei positionCount = 0; + QMatrix2x2 VP; + Simulation * simulation; FPS * fps; static bool AnyDialogOpen(); diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index b4da9f0..db34ab6 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -333,7 +333,7 @@ QWidget * MainWindow::buildSimulationUI() { timescaleSlider->setMinimum(1); timescaleSlider->setMaximum(500); substepsSlider->setMinimum(1); - substepsSlider->setMaximum(1000); + substepsSlider->setMaximum(100); resetSimulationControl(); @@ -433,7 +433,7 @@ void MainWindow::add() { void MainWindow::resetSimulationControl() { gravitySlider->setValue(981); timescaleSlider->setValue(100); - substepsSlider->setValue(30); + substepsSlider->setValue(5); } void MainWindow::toggleSimulation() { diff --git a/src/Pendulum.h b/src/Pendulum.h index c6159af..3fa2901 100644 --- a/src/Pendulum.h +++ b/src/Pendulum.h @@ -4,6 +4,7 @@ #include #include #include "Vector.h" +#include "GLWidget.h" class QPainter; @@ -16,6 +17,7 @@ public: void draw(QPainter*, double) const; void update(double, double); private: + friend class GLWidget; std::vector X, V; std::vector M, L; QColor color; diff --git a/src/Simulation.cpp b/src/Simulation.cpp index 9c3c727..48ae116 100644 --- a/src/Simulation.cpp +++ b/src/Simulation.cpp @@ -13,24 +13,10 @@ Simulation::Simulation() { lastUpdate = system_clock::now(); }; -void Simulation::draw(QPainter *p, int screenSize) { - pendulaMutex.lock(); - - double scale = screenSize * 0.95 / size; - - - - /* - for (const auto pendulum : pendula) - pendulum->draw(p, scale); - */ - - pendulaMutex.unlock(); -} - void Simulation::update() { auto thisUpdate = system_clock::now(); auto ms = (int)duration_cast(thisUpdate - lastUpdate).count(); + std::cout << ms << std::endl; lastUpdate = thisUpdate; if (!isPlaying) @@ -40,23 +26,29 @@ void Simulation::update() { h /= substeps; + pendulaMutex.lock(); + #pragma omp parallel for - for (int i = 0; i < pendula.size(); i++) // NOLINT(*-loop-convert) // no ranged based for msvc + for (int i = 0; i < pendula.size(); i++){ // NOLINT(*-loop-convert) // not ranged based for msvc for (int k = 0; k < substeps; k++) pendula[i]->update(h, gravity); + } + + emit positionChanged(&pendula); } void Simulation::clearPendula() { pendulaMutex.lock(); - for (auto p : pendula) + for (Pendulum* &p : pendula){ delete p; + p = nullptr; + } + pendula.clear(); pendula.shrink_to_fit(); - pendulaMutex.unlock(); - - emit pendulaChanged(pendula); + emit layoutChanged(&pendula); } void Simulation::addPendula(const std::vector &add) { @@ -65,8 +57,6 @@ void Simulation::addPendula(const std::vector &add) { for (auto p : add) pendula.push_back(p); - pendulaMutex.unlock(); - - emit pendulaChanged(pendula); + emit layoutChanged(&pendula); } diff --git a/src/Simulation.h b/src/Simulation.h index 8042fb7..ae35439 100644 --- a/src/Simulation.h +++ b/src/Simulation.h @@ -23,16 +23,16 @@ public: bool isPlaying = false; - void draw(QPainter*, int); + std::mutex pendulaMutex; signals: - void pendulaChanged(const std::vector &newPendula); + void layoutChanged(const std::vector *newPendula); + void positionChanged(const std::vector *changedPendula); public slots: void clearPendula(); void addPendula(const std::vector &add); private slots: void update(); private: - std::mutex pendulaMutex; QTimer * timer; int updateInterval = 17; std::vector pendula;