refactor: Migrate ViewCube to shader-based rendering
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
This commit is contained in:
217
src/ViewCube.cpp
217
src/ViewCube.cpp
@@ -1,18 +1,38 @@
|
||||
#include "ViewCube.h"
|
||||
#include <QPainter>
|
||||
#include <QFont>
|
||||
#include <QOpenGLShaderProgram>
|
||||
#include <QOpenGLTexture>
|
||||
#include <QVector>
|
||||
|
||||
ViewCube::ViewCube()
|
||||
{
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
m_faceTextures[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ViewCube::~ViewCube()
|
||||
{
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
delete m_faceTextures[i];
|
||||
}
|
||||
delete m_textureShaderProgram;
|
||||
m_cubeVbo.destroy();
|
||||
m_cubeVao.destroy();
|
||||
m_axesVbo.destroy();
|
||||
m_axesVao.destroy();
|
||||
}
|
||||
|
||||
void ViewCube::initializeGL()
|
||||
{
|
||||
initializeOpenGLFunctions();
|
||||
initShaders();
|
||||
createFaceTextures();
|
||||
setupBuffers();
|
||||
}
|
||||
|
||||
void ViewCube::paintGL(const QMatrix4x4& viewMatrix, int width, int height)
|
||||
void ViewCube::paintGL(QOpenGLShaderProgram* simpleShader, int simpleShaderColorLoc, const QMatrix4x4& viewMatrix, int width, int height)
|
||||
{
|
||||
int viewCubeSize = 150;
|
||||
glViewport(width - viewCubeSize, height - viewCubeSize, viewCubeSize, viewCubeSize);
|
||||
@@ -21,20 +41,13 @@ void ViewCube::paintGL(const QMatrix4x4& viewMatrix, int width, int height)
|
||||
QMatrix4x4 viewCubeProjection;
|
||||
viewCubeProjection.ortho(-2, 2, -2, 2, -10, 10);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadMatrixf(viewCubeProjection.constData());
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadMatrixf(viewMatrix.constData());
|
||||
|
||||
drawViewCube();
|
||||
drawAxes();
|
||||
drawViewCube(viewCubeProjection, viewMatrix);
|
||||
drawAxes(simpleShader, simpleShaderColorLoc, viewCubeProjection, viewMatrix);
|
||||
}
|
||||
|
||||
void ViewCube::createFaceTextures()
|
||||
{
|
||||
QStringList labels = {"FRONT", "BACK", "TOP", "BOTTOM", "RIGHT", "LEFT"};
|
||||
glGenTextures(6, faceTextures);
|
||||
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
QImage image(128, 128, QImage::Format_RGBA8888);
|
||||
@@ -45,94 +58,138 @@ void ViewCube::createFaceTextures()
|
||||
painter.setFont(QFont("Arial", 24, QFont::Bold));
|
||||
painter.drawText(image.rect(), Qt::AlignCenter, labels[i]);
|
||||
|
||||
QImage glImage = image.mirrored(false, true);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, faceTextures[i]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glImage.width(), glImage.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, glImage.bits());
|
||||
m_faceTextures[i] = new QOpenGLTexture(image.mirrored(false, true));
|
||||
m_faceTextures[i]->setMinificationFilter(QOpenGLTexture::Linear);
|
||||
m_faceTextures[i]->setMagnificationFilter(QOpenGLTexture::Linear);
|
||||
}
|
||||
}
|
||||
|
||||
void ViewCube::drawViewCube()
|
||||
void ViewCube::initShaders()
|
||||
{
|
||||
m_textureShaderProgram = new QOpenGLShaderProgram();
|
||||
if (!m_textureShaderProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/texture.vert")) {
|
||||
qCritical() << "ViewCube vertex shader compilation failed:" << m_textureShaderProgram->log();
|
||||
return;
|
||||
}
|
||||
if (!m_textureShaderProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/texture.frag")) {
|
||||
qCritical() << "ViewCube fragment shader compilation failed:" << m_textureShaderProgram->log();
|
||||
return;
|
||||
}
|
||||
if (!m_textureShaderProgram->link()) {
|
||||
qCritical() << "ViewCube shader program linking failed:" << m_textureShaderProgram->log();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ViewCube::setupBuffers()
|
||||
{
|
||||
float size = 0.75;
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glColor3f(1.0, 1.0, 1.0); // Use white so texture colors are not modulated
|
||||
|
||||
GLfloat vertices[] = {
|
||||
// positions // texture Coords
|
||||
// Front face
|
||||
glBindTexture(GL_TEXTURE_2D, faceTextures[0]);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.0, 0.0); glVertex3f(-size, -size, size);
|
||||
glTexCoord2f(1.0, 0.0); glVertex3f(size, -size, size);
|
||||
glTexCoord2f(1.0, 1.0); glVertex3f(size, size, size);
|
||||
glTexCoord2f(0.0, 1.0); glVertex3f(-size, size, size);
|
||||
glEnd();
|
||||
|
||||
-size, -size, size, 0.0f, 0.0f,
|
||||
size, -size, size, 1.0f, 0.0f,
|
||||
size, size, size, 1.0f, 1.0f,
|
||||
-size, size, size, 0.0f, 1.0f,
|
||||
// Back face
|
||||
glBindTexture(GL_TEXTURE_2D, faceTextures[1]);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(1.0, 0.0); glVertex3f(-size, -size, -size);
|
||||
glTexCoord2f(1.0, 1.0); glVertex3f(-size, size, -size);
|
||||
glTexCoord2f(0.0, 1.0); glVertex3f(size, size, -size);
|
||||
glTexCoord2f(0.0, 0.0); glVertex3f(size, -size, -size);
|
||||
glEnd();
|
||||
|
||||
-size, -size, -size, 1.0f, 0.0f,
|
||||
-size, size, -size, 1.0f, 1.0f,
|
||||
size, size, -size, 0.0f, 1.0f,
|
||||
size, -size, -size, 0.0f, 0.0f,
|
||||
// Top face
|
||||
glBindTexture(GL_TEXTURE_2D, faceTextures[2]);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.0, 1.0); glVertex3f(-size, size, -size);
|
||||
glTexCoord2f(0.0, 0.0); glVertex3f(-size, size, size);
|
||||
glTexCoord2f(1.0, 0.0); glVertex3f(size, size, size);
|
||||
glTexCoord2f(1.0, 1.0); glVertex3f(size, size, -size);
|
||||
glEnd();
|
||||
|
||||
-size, size, -size, 0.0f, 1.0f,
|
||||
-size, size, size, 0.0f, 0.0f,
|
||||
size, size, size, 1.0f, 0.0f,
|
||||
size, size, -size, 1.0f, 1.0f,
|
||||
// Bottom face
|
||||
glBindTexture(GL_TEXTURE_2D, faceTextures[3]);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(1.0, 1.0); glVertex3f(-size, -size, -size);
|
||||
glTexCoord2f(0.0, 1.0); glVertex3f(size, -size, -size);
|
||||
glTexCoord2f(0.0, 0.0); glVertex3f(size, -size, size);
|
||||
glTexCoord2f(1.0, 0.0); glVertex3f(-size, -size, size);
|
||||
glEnd();
|
||||
|
||||
-size, -size, -size, 1.0f, 1.0f,
|
||||
size, -size, -size, 0.0f, 1.0f,
|
||||
size, -size, size, 0.0f, 0.0f,
|
||||
-size, -size, size, 1.0f, 0.0f,
|
||||
// Right face
|
||||
glBindTexture(GL_TEXTURE_2D, faceTextures[4]);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(1.0, 0.0); glVertex3f(size, -size, -size);
|
||||
glTexCoord2f(1.0, 1.0); glVertex3f(size, size, -size);
|
||||
glTexCoord2f(0.0, 1.0); glVertex3f(size, size, size);
|
||||
glTexCoord2f(0.0, 0.0); glVertex3f(size, -size, size);
|
||||
glEnd();
|
||||
|
||||
size, -size, -size, 1.0f, 0.0f,
|
||||
size, size, -size, 1.0f, 1.0f,
|
||||
size, size, size, 0.0f, 1.0f,
|
||||
size, -size, size, 0.0f, 0.0f,
|
||||
// Left face
|
||||
glBindTexture(GL_TEXTURE_2D, faceTextures[5]);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.0, 0.0); glVertex3f(-size, -size, -size);
|
||||
glTexCoord2f(1.0, 0.0); glVertex3f(-size, -size, size);
|
||||
glTexCoord2f(1.0, 1.0); glVertex3f(-size, size, size);
|
||||
glTexCoord2f(0.0, 1.0); glVertex3f(-size, size, -size);
|
||||
glEnd();
|
||||
-size, -size, -size, 0.0f, 0.0f,
|
||||
-size, -size, size, 1.0f, 0.0f,
|
||||
-size, size, size, 1.0f, 1.0f,
|
||||
-size, size, -size, 0.0f, 1.0f,
|
||||
};
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
m_cubeVao.create();
|
||||
QOpenGLVertexArrayObject::Binder vaoBinder(&m_cubeVao);
|
||||
m_cubeVbo.create();
|
||||
m_cubeVbo.bind();
|
||||
m_cubeVbo.allocate(vertices, sizeof(vertices));
|
||||
|
||||
m_textureShaderProgram->enableAttributeArray(0);
|
||||
m_textureShaderProgram->setAttributeBuffer(0, GL_FLOAT, 0, 3, 5 * sizeof(GLfloat));
|
||||
m_textureShaderProgram->enableAttributeArray(1);
|
||||
m_textureShaderProgram->setAttributeBuffer(1, GL_FLOAT, 3 * sizeof(GLfloat), 2, 5 * sizeof(GLfloat));
|
||||
m_cubeVbo.release();
|
||||
|
||||
GLfloat axes_vertices[] = {
|
||||
0.0f, 0.0f, 0.0f, 1.5f, 0.0f, 0.0f, // X
|
||||
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.5f, // Y
|
||||
0.0f, 0.0f, 0.0f, 0.0f, 1.5f, 0.0f // Z
|
||||
};
|
||||
|
||||
m_axesVao.create();
|
||||
QOpenGLVertexArrayObject::Binder axesVaoBinder(&m_axesVao);
|
||||
m_axesVbo.create();
|
||||
m_axesVbo.bind();
|
||||
m_axesVbo.allocate(axes_vertices, sizeof(axes_vertices));
|
||||
m_axesVbo.release();
|
||||
}
|
||||
|
||||
void ViewCube::drawAxes()
|
||||
void ViewCube::drawViewCube(const QMatrix4x4& projection, const QMatrix4x4& view)
|
||||
{
|
||||
if (!m_textureShaderProgram || !m_textureShaderProgram->isLinked()) return;
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
m_textureShaderProgram->bind();
|
||||
m_textureShaderProgram->setUniformValue("projectionMatrix", projection);
|
||||
m_textureShaderProgram->setUniformValue("modelViewMatrix", view);
|
||||
m_textureShaderProgram->setUniformValue("texture_diffuse1", 0);
|
||||
|
||||
QOpenGLVertexArrayObject::Binder vaoBinder(&m_cubeVao);
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
m_faceTextures[i]->bind();
|
||||
glDrawArrays(GL_QUADS, i * 4, 4);
|
||||
}
|
||||
m_textureShaderProgram->release();
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
|
||||
void ViewCube::drawAxes(QOpenGLShaderProgram* simpleShader, int colorLoc, const QMatrix4x4& projection, const QMatrix4x4& view)
|
||||
{
|
||||
if (!simpleShader || !simpleShader->isLinked()) return;
|
||||
|
||||
simpleShader->bind();
|
||||
simpleShader->setUniformValue("projectionMatrix", projection);
|
||||
simpleShader->setUniformValue("modelViewMatrix", view);
|
||||
|
||||
QOpenGLVertexArrayObject::Binder vaoBinder(&m_axesVao);
|
||||
m_axesVbo.bind();
|
||||
simpleShader->enableAttributeArray(0);
|
||||
simpleShader->setAttributeBuffer(0, GL_FLOAT, 0, 3, 3 * sizeof(GLfloat));
|
||||
m_axesVbo.release();
|
||||
|
||||
glLineWidth(2.0f);
|
||||
glBegin(GL_LINES);
|
||||
|
||||
// X-axis (red)
|
||||
glColor3f(1.0, 0.0, 0.0);
|
||||
glVertex3f(0.0, 0.0, 0.0);
|
||||
glVertex3f(1.5, 0.0, 0.0);
|
||||
simpleShader->setUniformValue(colorLoc, QVector4D(1.0f, 0.0f, 0.0f, 1.0f));
|
||||
glDrawArrays(GL_LINES, 0, 2);
|
||||
|
||||
// Y-axis (green)
|
||||
glColor3f(0.0, 1.0, 0.0);
|
||||
glVertex3f(0.0, 0.0, 0.0);
|
||||
glVertex3f(0.0, 0.0, 1.5);
|
||||
simpleShader->setUniformValue(colorLoc, QVector4D(0.0f, 1.0f, 0.0f, 1.0f));
|
||||
glDrawArrays(GL_LINES, 2, 2);
|
||||
|
||||
// Z-axis (blue)
|
||||
glColor3f(0.0, 0.0, 1.0);
|
||||
glVertex3f(0.0, 0.0, 0.0);
|
||||
glVertex3f(0.0, 1.5, 0.0);
|
||||
glEnd();
|
||||
simpleShader->setUniformValue(colorLoc, QVector4D(0.0f, 0.0f, 1.0f, 1.0f));
|
||||
glDrawArrays(GL_LINES, 4, 2);
|
||||
|
||||
glLineWidth(1.0f);
|
||||
}
|
||||
|
||||
@@ -3,22 +3,37 @@
|
||||
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QMatrix4x4>
|
||||
#include <qopengl.h> // For GLuint
|
||||
#include <QOpenGLVertexArrayObject>
|
||||
#include <QOpenGLBuffer>
|
||||
|
||||
class QOpenGLShaderProgram;
|
||||
class QOpenGLTexture;
|
||||
|
||||
class ViewCube : protected QOpenGLFunctions
|
||||
{
|
||||
public:
|
||||
ViewCube();
|
||||
~ViewCube();
|
||||
|
||||
void initializeGL();
|
||||
void paintGL(const QMatrix4x4& viewMatrix, int width, int height);
|
||||
void paintGL(QOpenGLShaderProgram* simpleShader, int simpleShaderColorLoc, const QMatrix4x4& viewMatrix, int width, int height);
|
||||
|
||||
private:
|
||||
void createFaceTextures();
|
||||
void drawViewCube();
|
||||
void drawAxes();
|
||||
void initShaders();
|
||||
void setupBuffers();
|
||||
void drawViewCube(const QMatrix4x4& projection, const QMatrix4x4& view);
|
||||
void drawAxes(QOpenGLShaderProgram* simpleShader, int colorLoc, const QMatrix4x4& projection, const QMatrix4x4& view);
|
||||
|
||||
GLuint faceTextures[6];
|
||||
QOpenGLTexture* m_faceTextures[6];
|
||||
|
||||
QOpenGLShaderProgram* m_textureShaderProgram = nullptr;
|
||||
|
||||
QOpenGLVertexArrayObject m_cubeVao;
|
||||
QOpenGLBuffer m_cubeVbo;
|
||||
|
||||
QOpenGLVertexArrayObject m_axesVao;
|
||||
QOpenGLBuffer m_axesVbo;
|
||||
};
|
||||
|
||||
#endif // VIEWCUBE_H
|
||||
|
||||
@@ -245,11 +245,11 @@ void ViewportWidget::paintGL()
|
||||
|
||||
m_shaderProgram->release();
|
||||
|
||||
// View cube rendering - temporarily disabled as it uses the fixed-function pipeline
|
||||
// QMatrix4x4 viewCubeModel;
|
||||
// viewCubeModel.rotate(m_camera->xRotation() / 16.0f, 1, 0, 0);
|
||||
// viewCubeModel.rotate(m_camera->yRotation() / 16.0f, 0, 1, 0);
|
||||
// m_viewCube->paintGL(viewCubeModel, width(), height());
|
||||
// View cube rendering
|
||||
QMatrix4x4 viewCubeModel;
|
||||
viewCubeModel.rotate(m_camera->xRotation() / 16.0f, 1, 0, 0);
|
||||
viewCubeModel.rotate(m_camera->yRotation() / 16.0f, 0, 1, 0);
|
||||
m_viewCube->paintGL(m_shaderProgram, m_colorLoc, viewCubeModel, width(), height());
|
||||
|
||||
glViewport(0, 0, width(), height());
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
12
src/shaders/texture.frag
Normal file
12
src/shaders/texture.frag
Normal file
@@ -0,0 +1,12 @@
|
||||
#version 330 core
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
in vec2 TexCoord;
|
||||
|
||||
uniform sampler2D texture_diffuse1;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = texture(texture_diffuse1, TexCoord);
|
||||
}
|
||||
15
src/shaders/texture.vert
Normal file
15
src/shaders/texture.vert
Normal file
@@ -0,0 +1,15 @@
|
||||
#version 330 core
|
||||
|
||||
layout (location = 0) in vec3 aPos;
|
||||
layout (location = 1) in vec2 aTexCoord;
|
||||
|
||||
out vec2 TexCoord;
|
||||
|
||||
uniform mat4 modelViewMatrix;
|
||||
uniform mat4 projectionMatrix;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(aPos, 1.0);
|
||||
TexCoord = aTexCoord;
|
||||
}
|
||||
Reference in New Issue
Block a user