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);