|
|
@ -7,29 +7,59 @@ |
|
|
|
#include <QApplication> |
|
|
|
#include <QApplication> |
|
|
|
#include <QDialog> |
|
|
|
#include <QDialog> |
|
|
|
#include "FPS.h" |
|
|
|
#include "FPS.h" |
|
|
|
|
|
|
|
#include <QOpenGLShaderProgram> |
|
|
|
|
|
|
|
|
|
|
|
GLWidget::GLWidget(Simulation * simulation) : simulation(simulation) { |
|
|
|
GLWidget::GLWidget(Simulation * simulation) : simulation(simulation) { |
|
|
|
startTimer(1000 / 144); |
|
|
|
startTimer(1000 / 144); |
|
|
|
fps = new FPS; |
|
|
|
fps = new FPS; |
|
|
|
fps->setUpdateInterval(500); |
|
|
|
fps->setUpdateInterval(500); |
|
|
|
|
|
|
|
connect(simulation, &Simulation::layoutChanged, this, &GLWidget::initGPUMemory); |
|
|
|
|
|
|
|
connect(simulation, &Simulation::positionChanged, this, &GLWidget::changePosition); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void GLWidget::paintEvent(QPaintEvent *e) { |
|
|
|
void GLWidget::initializeGL() { |
|
|
|
fps->newFrame(); |
|
|
|
initializeOpenGLFunctions(); |
|
|
|
QString fpsString = "FPS: " + QString::fromStdString(std::to_string(fps->current)); |
|
|
|
|
|
|
|
|
|
|
|
program = new QOpenGLShaderProgram; |
|
|
|
|
|
|
|
program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/vertex.glsl"); |
|
|
|
|
|
|
|
program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/fragment.glsl"); |
|
|
|
|
|
|
|
program->link(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
glGenVertexArrays(1, &VAO); |
|
|
|
|
|
|
|
glGenBuffers(1, &positionVBO); |
|
|
|
|
|
|
|
glGenBuffers(1, &colorVBO); |
|
|
|
|
|
|
|
glGenBuffers(1, &EBO); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void GLWidget::paintGL() { |
|
|
|
auto p = new QPainter(this); |
|
|
|
auto p = new QPainter(this); |
|
|
|
p->setRenderHint(QPainter::Antialiasing); |
|
|
|
p->setRenderHint(QPainter::Antialiasing); |
|
|
|
p->fillRect(e->rect(), QColor(30, 30, 30)); |
|
|
|
p->beginNativePainting(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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, indexCount, GL_UNSIGNED_INT, nullptr); |
|
|
|
|
|
|
|
glBindVertexArray(0); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
p->endNativePainting(); |
|
|
|
|
|
|
|
|
|
|
|
p->setPen(Qt::white); |
|
|
|
p->setPen(Qt::white); |
|
|
|
auto font = p->font(); |
|
|
|
auto font = p->font(); |
|
|
|
font.setPixelSize(20); |
|
|
|
font.setPixelSize(20); |
|
|
|
p->setFont(font); |
|
|
|
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(); |
|
|
|
p->end(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -46,4 +76,100 @@ bool GLWidget::AnyDialogOpen() { |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void GLWidget::initGPUMemory(const std::vector<Pendulum *> *pendula) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<float> positions; |
|
|
|
|
|
|
|
std::vector<float> colors; |
|
|
|
|
|
|
|
std::vector<float> massRadii; |
|
|
|
|
|
|
|
std::vector<GLuint> 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); |
|
|
|
|
|
|
|
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<Pendulum *> *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; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|