refactor: Extract view cube rendering to dedicated class

Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
This commit is contained in:
2026-02-09 16:04:40 -07:00
parent be35ae3196
commit 732a7bd428
5 changed files with 177 additions and 131 deletions

View File

@@ -14,6 +14,7 @@ add_executable(OpenCAD
src/main.cpp
src/MainWindow.cpp
src/ViewportWidget.cpp
src/ViewCube.cpp
)
target_link_libraries(OpenCAD PRIVATE Qt6::Widgets Qt6::OpenGLWidgets)

138
src/ViewCube.cpp Normal file
View File

@@ -0,0 +1,138 @@
#include "ViewCube.h"
#include <QPainter>
#include <QFont>
ViewCube::ViewCube()
{
}
void ViewCube::initializeGL()
{
initializeOpenGLFunctions();
createFaceTextures();
}
void ViewCube::paintGL(const QMatrix4x4& viewMatrix, int width, int height)
{
int viewCubeSize = 150;
glViewport(width - viewCubeSize, height - viewCubeSize, viewCubeSize, viewCubeSize);
glClear(GL_DEPTH_BUFFER_BIT);
QMatrix4x4 viewCubeProjection;
viewCubeProjection.ortho(-2, 2, -2, 2, -10, 10);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(viewCubeProjection.constData());
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(viewMatrix.constData());
drawViewCube();
drawAxes();
}
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);
image.fill(qRgba(204, 204, 204, 255)); // light gray background
QPainter painter(&image);
painter.setPen(Qt::black);
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());
}
}
void ViewCube::drawViewCube()
{
float size = 0.75;
glEnable(GL_TEXTURE_2D);
glColor3f(1.0, 1.0, 1.0); // Use white so texture colors are not modulated
// 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();
// 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();
// 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();
// 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();
// 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();
// 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();
glDisable(GL_TEXTURE_2D);
}
void ViewCube::drawAxes()
{
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);
// Y-axis (green)
glColor3f(0.0, 1.0, 0.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 1.5, 0.0);
// Z-axis (blue)
glColor3f(0.0, 0.0, 1.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, 1.5);
glEnd();
glLineWidth(1.0f);
}

24
src/ViewCube.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef VIEWCUBE_H
#define VIEWCUBE_H
#include <QOpenGLFunctions>
#include <QMatrix4x4>
#include <QtOpenGL/qgl.h> // For GLuint
class ViewCube : protected QOpenGLFunctions
{
public:
ViewCube();
void initializeGL();
void paintGL(const QMatrix4x4& viewMatrix, int width, int height);
private:
void createFaceTextures();
void drawViewCube();
void drawAxes();
GLuint faceTextures[6];
};
#endif // VIEWCUBE_H

View File

@@ -1,14 +1,18 @@
#include "ViewportWidget.h"
#include "ViewCube.h"
#include <QMouseEvent>
#include <QWheelEvent>
#include <QApplication>
#include <QPainter>
#include <QFontMetrics>
#include <QVector3D>
ViewportWidget::ViewportWidget(QWidget *parent)
: QOpenGLWidget(parent)
{
m_viewCube = new ViewCube();
}
ViewportWidget::~ViewportWidget()
{
delete m_viewCube;
}
void ViewportWidget::initializeGL()
@@ -16,7 +20,7 @@ void ViewportWidget::initializeGL()
initializeOpenGLFunctions();
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glEnable(GL_DEPTH_TEST);
createFaceTextures();
m_viewCube->initializeGL();
}
void ViewportWidget::paintGL()
@@ -40,26 +44,11 @@ void ViewportWidget::paintGL()
drawCube();
// View cube rendering in top right
int viewCubeSize = 150;
glViewport(width() - viewCubeSize, height() - viewCubeSize, viewCubeSize, viewCubeSize);
glClear(GL_DEPTH_BUFFER_BIT);
QMatrix4x4 viewCubeProjection;
viewCubeProjection.ortho(-2, 2, -2, 2, -10, 10);
// View cube rendering
QMatrix4x4 viewCubeModel;
viewCubeModel.rotate(xRot / 16.0f, 1, 0, 0);
viewCubeModel.rotate(yRot / 16.0f, 0, 1, 0);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(viewCubeProjection.constData());
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(viewCubeModel.constData());
drawViewCube();
drawAxes();
m_viewCube->paintGL(viewCubeModel, width(), height());
glViewport(0, 0, width(), height());
}
@@ -104,112 +93,6 @@ void ViewportWidget::wheelEvent(QWheelEvent *event)
update();
}
void ViewportWidget::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);
image.fill(qRgba(204, 204, 204, 255)); // light gray background
QPainter painter(&image);
painter.setPen(Qt::black);
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());
}
}
void ViewportWidget::drawViewCube()
{
float size = 0.75;
glEnable(GL_TEXTURE_2D);
glColor3f(1.0, 1.0, 1.0); // Use white so texture colors are not modulated
// 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();
// 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();
// 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();
// 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();
// 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();
// 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();
glDisable(GL_TEXTURE_2D);
}
void ViewportWidget::drawAxes()
{
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);
// Y-axis (green)
glColor3f(0.0, 1.0, 0.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 1.5, 0.0);
// Z-axis (blue)
glColor3f(0.0, 0.0, 1.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, 1.5);
glEnd();
glLineWidth(1.0f);
}
void ViewportWidget::drawCube()
{
glBegin(GL_QUADS);

View File

@@ -6,12 +6,15 @@
#include <QMatrix4x4>
#include <QPoint>
class ViewCube;
class ViewportWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
Q_OBJECT
public:
explicit ViewportWidget(QWidget *parent = nullptr);
~ViewportWidget();
protected:
void initializeGL() override;
@@ -24,12 +27,9 @@ protected:
private:
void drawCube();
void drawViewCube();
void drawAxes();
void createFaceTextures();
QMatrix4x4 projection;
GLuint faceTextures[6];
ViewCube* m_viewCube;
float xRot = 0;
float yRot = 0;