|
|
|
@ -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<Pendulum *> &addPendula) { |
|
|
|
|
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); |
|
|
|
|
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<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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|