|
|
|
@ -28,42 +28,69 @@ void GLWidget::initializeGL() { |
|
|
|
|
glGenVertexArrays(1, &VAO); |
|
|
|
|
glGenBuffers(1, &positionVBO); |
|
|
|
|
glGenBuffers(1, &colorVBO); |
|
|
|
|
glGenBuffers(1, &massRadiiVBO); |
|
|
|
|
glGenBuffers(1, &EBO); |
|
|
|
|
|
|
|
|
|
glEnable(GL_POINT_SPRITE); |
|
|
|
|
glEnable(GL_PROGRAM_POINT_SIZE); |
|
|
|
|
glEnable(GL_PRIMITIVE_RESTART); |
|
|
|
|
glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); |
|
|
|
|
glEnable(GL_DEPTH_TEST); |
|
|
|
|
glDepthFunc(GL_LESS); |
|
|
|
|
glDepthMask(GL_TRUE); |
|
|
|
|
glClearColor(.15, .15, .15, 1); |
|
|
|
|
|
|
|
|
|
std::vector<Pendulum*> empty; |
|
|
|
|
initGPUMemory(&empty); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void GLWidget::paintGL() { |
|
|
|
|
auto p = new QPainter(this); |
|
|
|
|
p->setRenderHint(QPainter::Antialiasing); |
|
|
|
|
p->beginNativePainting(); |
|
|
|
|
//auto p = new QPainter(this);
|
|
|
|
|
//p->setRenderHint(QPainter::Antialiasing);
|
|
|
|
|
//p->beginNativePainting();
|
|
|
|
|
|
|
|
|
|
glEnable(GL_PRIMITIVE_RESTART); |
|
|
|
|
glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); |
|
|
|
|
glClearColor(.15, .15, .15, 1); |
|
|
|
|
// Native OpenGL
|
|
|
|
|
{ |
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
|
|
|
|
|
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT); |
|
|
|
|
glViewport(0, 0, QWidget::width(), QWidget::height()); |
|
|
|
|
program->bind(); |
|
|
|
|
program->setUniformValue("VP", VP); |
|
|
|
|
|
|
|
|
|
program->bind(); |
|
|
|
|
program->setUniformValue("VP", VP); |
|
|
|
|
glBindVertexArray(VAO); |
|
|
|
|
glDrawElements(GL_LINE_STRIP, indexCount, GL_UNSIGNED_INT, nullptr); |
|
|
|
|
glBindVertexArray(0); |
|
|
|
|
glBindVertexArray(VAO); |
|
|
|
|
|
|
|
|
|
p->endNativePainting(); |
|
|
|
|
// Lines
|
|
|
|
|
{ |
|
|
|
|
program->setUniformValue("drawPoints", false); |
|
|
|
|
glDrawElements(GL_LINE_STRIP, indexCount, GL_UNSIGNED_INT, nullptr); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
p->setPen(Qt::white); |
|
|
|
|
auto font = p->font(); |
|
|
|
|
font.setPixelSize(20); |
|
|
|
|
p->setFont(font); |
|
|
|
|
// Mass Circles
|
|
|
|
|
if (showMasses) { |
|
|
|
|
program->setUniformValue("drawPoints", true); |
|
|
|
|
program->setUniformValue("depthOffset", depthOffset); |
|
|
|
|
program->setUniformValue("screenSizePixels", screenSizePixels * 0.9f); |
|
|
|
|
program->setUniformValue("screenSizeMeters", float(simulation->sizeMeters)); |
|
|
|
|
glDrawElements(GL_POINTS, indexCount, GL_UNSIGNED_INT, nullptr); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fps->newFrame(); |
|
|
|
|
QString fpsString = "FPS: " + QString::fromStdString(std::to_string(fps->current)); |
|
|
|
|
glBindVertexArray(0); |
|
|
|
|
} |
|
|
|
|
//p->endNativePainting();
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
// FPS
|
|
|
|
|
{ |
|
|
|
|
p->setPen(Qt::white); |
|
|
|
|
auto font = p->font(); |
|
|
|
|
font.setPixelSize(20); |
|
|
|
|
p->setFont(font); |
|
|
|
|
fps->newFrame(); |
|
|
|
|
QString fpsString = "FPS: " + QString::fromStdString(std::to_string(fps->current)); |
|
|
|
|
p->drawText(0, 0, 100, 100, Qt::AlignTop | Qt::AlignLeft, fpsString); |
|
|
|
|
} |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
p->drawText(0, 0, 100, 100, Qt::AlignTop | Qt::AlignLeft, fpsString); |
|
|
|
|
p->end(); |
|
|
|
|
//p->end();
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void GLWidget::timerEvent(QTimerEvent *e) { |
|
|
|
@ -81,43 +108,59 @@ bool GLWidget::AnyDialogOpen() { |
|
|
|
|
|
|
|
|
|
void GLWidget::initGPUMemory(const std::vector<Pendulum *> *pendula) { |
|
|
|
|
|
|
|
|
|
int segmentCount = std::transform_reduce(pendula->begin(), pendula->end(), 0, [](int prev, int curr){ |
|
|
|
|
return prev + curr + 1; |
|
|
|
|
}, [](const Pendulum * p){ |
|
|
|
|
return p->X.size(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
std::vector<float> positions; |
|
|
|
|
std::vector<float> colors; |
|
|
|
|
std::vector<float> massRadii; |
|
|
|
|
std::vector<GLuint> indices; |
|
|
|
|
|
|
|
|
|
GLuint index = 0; |
|
|
|
|
for (const auto p : *pendula){ |
|
|
|
|
if (!pendula->empty()){ |
|
|
|
|
|
|
|
|
|
// Origin point
|
|
|
|
|
positions.push_back(0); |
|
|
|
|
positions.push_back(0); |
|
|
|
|
float depth = 1.f - 1.f / float(segmentCount); |
|
|
|
|
depthOffset = 1.f * 2 / float(segmentCount); |
|
|
|
|
|
|
|
|
|
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++); |
|
|
|
|
GLuint index = 0; |
|
|
|
|
for (const auto p : *pendula){ |
|
|
|
|
|
|
|
|
|
// 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)); |
|
|
|
|
// Origin point
|
|
|
|
|
positions.push_back(0); |
|
|
|
|
positions.push_back(0); |
|
|
|
|
positions.push_back(depth); |
|
|
|
|
depth -= depthOffset; |
|
|
|
|
|
|
|
|
|
colors.resize(colors.size() + 3); |
|
|
|
|
red = &colors.back() - 2; |
|
|
|
|
float * red = &colors.back() - 2; |
|
|
|
|
p->color.getRgbF(red, red + 1, red + 2); |
|
|
|
|
|
|
|
|
|
massRadii.push_back(float(p->M[segment])); |
|
|
|
|
massRadii.push_back(0); |
|
|
|
|
|
|
|
|
|
indices.push_back(index++); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Primitive Restart
|
|
|
|
|
indices.push_back(0xFFFFFFFF); |
|
|
|
|
// 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)); |
|
|
|
|
positions.push_back(depth); |
|
|
|
|
depth -= depthOffset; |
|
|
|
|
|
|
|
|
|
colors.resize(colors.size() + 3); |
|
|
|
|
red = &colors.back() - 2; |
|
|
|
|
p->color.getRgbF(red, red + 1, red + 2); |
|
|
|
|
|
|
|
|
|
massRadii.push_back(float(sqrt(p->M[segment]) / 5)); |
|
|
|
|
|
|
|
|
|
indices.push_back(index++); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Primitive Restart
|
|
|
|
|
indices.push_back(0xFFFFFFFF); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
indexCount = GLsizei(indices.size()); |
|
|
|
@ -127,7 +170,7 @@ void GLWidget::initGPUMemory(const std::vector<Pendulum *> *pendula) { |
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr); |
|
|
|
|
glEnableVertexAttribArray(0); |
|
|
|
|
|
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, colorVBO); |
|
|
|
@ -135,6 +178,11 @@ void GLWidget::initGPUMemory(const std::vector<Pendulum *> *pendula) { |
|
|
|
|
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr); |
|
|
|
|
glEnableVertexAttribArray(1); |
|
|
|
|
|
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, massRadiiVBO); |
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, GLsizeiptr(massRadii.size() * sizeof(float)), massRadii.data(), GL_STATIC_DRAW); |
|
|
|
|
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 1 * sizeof(float), nullptr); |
|
|
|
|
glEnableVertexAttribArray(2); |
|
|
|
|
|
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); |
|
|
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, GLsizeiptr(indices.size() * sizeof(GLuint)), indices.data(), GL_STATIC_DRAW); |
|
|
|
|
|
|
|
|
@ -152,10 +200,11 @@ void GLWidget::changePosition(const std::vector<Pendulum *> *pendula) { |
|
|
|
|
if (positions){ |
|
|
|
|
size_t index = 0; |
|
|
|
|
for (const auto p : *pendula){ |
|
|
|
|
index += 2; |
|
|
|
|
index += 3; |
|
|
|
|
for (auto x : p->X){ |
|
|
|
|
positions[index++] = float(x.x); |
|
|
|
|
positions[index++] = float(x.y); |
|
|
|
|
index++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -165,13 +214,20 @@ void GLWidget::changePosition(const std::vector<Pendulum *> *pendula) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void GLWidget::resizeGL(int w, int h) { |
|
|
|
|
float m = std::min(float(w), float(h)); |
|
|
|
|
float scale = 1 / (float(simulation->size) / 2) * 0.9f; |
|
|
|
|
screenSizePixels = std::min(float(w), float(h)); |
|
|
|
|
float scale = screenSizePixels / float(simulation->sizeMeters) * 2 * 0.9f; |
|
|
|
|
|
|
|
|
|
VP.setToIdentity(); |
|
|
|
|
VP(0, 0) = 1 / float(w); |
|
|
|
|
VP(1, 1) = -1 / float(h); |
|
|
|
|
VP *= m * scale; |
|
|
|
|
VP *= scale; |
|
|
|
|
VP(2, 2) = 1; |
|
|
|
|
|
|
|
|
|
glViewport(0, 0, w, h); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void GLWidget::showMassesChanged(int state) { |
|
|
|
|
showMasses = state == Qt::Checked; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|