parent
a99effbeb6
commit
8d1c374b0f
17 changed files with 357 additions and 72 deletions
@ -0,0 +1,11 @@ |
||||
#version 330 core |
||||
|
||||
out vec4 FragColor; |
||||
|
||||
in vec2 texCoord; |
||||
|
||||
uniform sampler2D quadTexture; |
||||
|
||||
void main() { |
||||
FragColor = texture(quadTexture, texCoord); |
||||
} |
@ -1,6 +1,8 @@ |
||||
<RCC> |
||||
<qresource prefix="/shaders/"> |
||||
<file>vertex.glsl</file> |
||||
<file>fragment.glsl</file> |
||||
<file>vertex_pendula.glsl</file> |
||||
<file>fragment_pendula.glsl</file> |
||||
<file>vertex_quad.glsl</file> |
||||
<file>fragment_quad.glsl</file> |
||||
</qresource> |
||||
</RCC> |
@ -0,0 +1,11 @@ |
||||
#version 330 core |
||||
|
||||
layout (location = 0) in vec2 vPos; |
||||
layout (location = 1) in vec2 vTex; |
||||
|
||||
out vec2 texCoord; |
||||
|
||||
void main() { |
||||
gl_Position = vec4(vPos, 0, 1); |
||||
texCoord = vTex; |
||||
} |
@ -0,0 +1,177 @@ |
||||
#include "Overlay.h" |
||||
#include "FPS.h" |
||||
#include <QPainter> |
||||
#include <QOpenGLShaderProgram> |
||||
#include "Simulation.h" |
||||
#include <iostream> |
||||
#include <QOpenGLTexture> |
||||
#include <sstream> |
||||
#include <iomanip> |
||||
|
||||
Overlay::Overlay(Simulation * simulation) : simulation(simulation) { |
||||
fps = new FPS; |
||||
fps->setUpdateInterval(500); |
||||
} |
||||
|
||||
void Overlay::init() { |
||||
initializeOpenGLFunctions(); |
||||
|
||||
program = new QOpenGLShaderProgram; |
||||
program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/vertex_quad.glsl"); |
||||
program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/fragment_quad.glsl"); |
||||
program->link(); |
||||
|
||||
float quadVertices[] = { |
||||
-1, 1, 0, 1, // top left
|
||||
-1, -1, 0, 0, // bottom left
|
||||
1, -1, 1, 0, // bottom right
|
||||
1, 1, 1, 1 // top right
|
||||
}; |
||||
|
||||
GLuint indices[] = { |
||||
0, 1, 2, 2, 3, 0 |
||||
}; |
||||
|
||||
glGenVertexArrays(1, &VAO); |
||||
glBindVertexArray(VAO); |
||||
|
||||
GLuint VBO; |
||||
glGenBuffers(1, &VBO); |
||||
glBindBuffer(GL_ARRAY_BUFFER, VBO); |
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), quadVertices, GL_STATIC_DRAW); |
||||
|
||||
GLuint EBO; |
||||
glGenBuffers(1, &EBO); |
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); |
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); |
||||
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), nullptr); |
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (GLvoid*) (2 * sizeof(float))); |
||||
glEnableVertexAttribArray(0); |
||||
glEnableVertexAttribArray(1); |
||||
|
||||
glBindVertexArray(0); |
||||
} |
||||
|
||||
void Overlay::draw() { |
||||
int w = viewportSize.width(); |
||||
int h = (viewportSize.height() - simulationRect.height()) / 2; |
||||
|
||||
// Top HUD with Energy Plot
|
||||
{ |
||||
glViewport(0, viewportSize.height() - h, w, h); |
||||
|
||||
QImage hud(w, h, QImage::Format_RGBA8888); |
||||
hud.fill(Qt::transparent); |
||||
|
||||
QPainter p(&hud); |
||||
p.setRenderHints(QPainter::Antialiasing); |
||||
p.setPen(Qt::white); |
||||
auto font = p.font(); |
||||
font.setPixelSize(15); |
||||
p.setFont(font); |
||||
|
||||
auto m = p.fontMetrics(); |
||||
|
||||
double pot = simulation->potentialEnergy; |
||||
double kin = simulation->kineticEnergy; |
||||
double total = pot + kin; |
||||
|
||||
QColor empty(50, 50, 50); |
||||
QColor full(80, 80, 80); |
||||
|
||||
// Total energy bar
|
||||
{ |
||||
double lossPercentage = (1 - total / energyLimit) * 100; |
||||
|
||||
std::stringstream text; |
||||
text << std::fixed << std::setprecision(0) << "Total Energy: " << total << " J"; |
||||
text << " --- "; |
||||
text << "Loss: " << std::setprecision(1) << lossPercentage << " %"; |
||||
QString totalText = QString::fromStdString(text.str()); |
||||
|
||||
int x = int(total / energyLimit * w); |
||||
|
||||
p.fillRect(0, 0, w, h / 2, empty); |
||||
p.fillRect(0, 0, x, h / 2, full); |
||||
p.drawLine(x, 0, x, h / 2); |
||||
p.drawText(0, 0, w, h / 2, Qt::AlignCenter | Qt::AlignVCenter, totalText); |
||||
} |
||||
|
||||
// Split energy bar
|
||||
{ |
||||
int potX = total == 0 ? int(0.5 * w) : int(pot / total * w); |
||||
p.fillRect(0, h / 2, w, h / 2, empty); |
||||
p.fillRect(0, h / 2, potX, h / 2, full); |
||||
|
||||
std::stringstream text; |
||||
text << std::fixed << std::setprecision(0) << "Potential: " << pot << " J"; |
||||
QString potText = QString::fromStdString(text.str()); |
||||
|
||||
text = std::stringstream(); |
||||
text << std::fixed << std::setprecision(0) << "Kinetic: " << kin << " J"; |
||||
QString kinText = QString::fromStdString(text.str()); |
||||
|
||||
int textWidth1 = m.horizontalAdvance(potText); |
||||
int textWidth2 = m.horizontalAdvance(kinText); |
||||
int x1 = (w - textWidth1) / 4; |
||||
int x2 = (w - textWidth2) / 4 * 3; |
||||
|
||||
p.drawLine(potX, h / 2, potX, h); |
||||
p.drawText(x1, h / 2, textWidth1, h / 2, Qt::AlignCenter | Qt::AlignVCenter, potText); |
||||
p.drawText(x2, h / 2, textWidth2, h / 2, Qt::AlignCenter | Qt::AlignVCenter, kinText); |
||||
} |
||||
|
||||
p.drawLine(0, 0, w, 0); |
||||
p.drawLine(0, h / 2, w, h / 2); |
||||
p.drawLine(0, h, w, h); |
||||
|
||||
drawTexture(&hud); |
||||
} |
||||
|
||||
// Bottom HUD with FPS and UPS
|
||||
{ |
||||
glViewport(0, 0, w, h); |
||||
|
||||
QImage hud(w, h, QImage::Format_RGBA8888); |
||||
|
||||
// Background
|
||||
hud.fill(Qt::transparent); |
||||
|
||||
QPainter p(&hud); |
||||
p.setRenderHints(QPainter::Antialiasing); |
||||
|
||||
// FPS
|
||||
{ |
||||
p.setPen(Qt::white); |
||||
auto font = p.font(); |
||||
font.setPixelSize(15); |
||||
p.setFont(font); |
||||
fps->newFrame(); |
||||
std::stringstream text; |
||||
text << "FPS: " << fps->current << "\n"; |
||||
text << "UPS: " << simulation->ups->current; |
||||
p.drawText(0, 0, 100, h, Qt::AlignBottom | Qt::AlignLeft, QString::fromStdString(text.str())); |
||||
} |
||||
drawTexture(&hud); |
||||
} |
||||
} |
||||
|
||||
void Overlay::resize(QSize newViewportSize, QRect newSimulationRect) { |
||||
viewportSize = newViewportSize; |
||||
simulationRect = newSimulationRect; |
||||
} |
||||
|
||||
void Overlay::drawTexture(QImage *image) { |
||||
glBindVertexArray(VAO); |
||||
program->bind(); |
||||
|
||||
QOpenGLTexture texture(image->mirrored()); |
||||
texture.bind(); |
||||
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr); |
||||
} |
||||
|
||||
void Overlay::fetchEnergyLimit() { |
||||
energyLimit = simulation->kineticEnergy + simulation->potentialEnergy; |
||||
} |
@ -0,0 +1,29 @@ |
||||
#include <QRect> |
||||
|
||||
#include <QOpenGLExtraFunctions> |
||||
|
||||
class QOpenGLWidget; |
||||
class FPS; |
||||
class QOpenGLShaderProgram; |
||||
class QOpenGLTexture; |
||||
class Simulation; |
||||
|
||||
class Overlay : public QObject, protected QOpenGLExtraFunctions { |
||||
Q_OBJECT |
||||
|
||||
FPS * fps; |
||||
QSize viewportSize; |
||||
QRect simulationRect; |
||||
QOpenGLShaderProgram * program; |
||||
GLuint VAO; |
||||
void drawTexture(QImage *image); |
||||
Simulation * simulation; |
||||
double energyLimit = 0; |
||||
public slots: |
||||
void fetchEnergyLimit(); |
||||
public: |
||||
explicit Overlay(Simulation *); |
||||
void init(); |
||||
void draw(); |
||||
void resize(QSize newViewportSize, QRect newSimulationRect); |
||||
}; |
Loading…
Reference in new issue