Files
unnamed-cad-software/src/ViewCube.cpp
2026-02-17 16:49:49 -07:00

213 lines
6.9 KiB
C++

#include "ViewCube.h"
#include <QGuiApplication>
#include <QPainter>
#include <QFont>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QScreen>
#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(QOpenGLShaderProgram* simpleShader, int simpleShaderColorLoc, const QMatrix4x4& viewMatrix, int width, int height, const QPoint& mousePos)
{
int viewCubeSize = 150 * QGuiApplication::primaryScreen()->devicePixelRatio();
glViewport(width - viewCubeSize, height - viewCubeSize, viewCubeSize, viewCubeSize);
QRect viewCubeRect(width - viewCubeSize, 0, viewCubeSize, viewCubeSize);
QPoint physicalMousePos = mousePos * QGuiApplication::primaryScreen()->devicePixelRatio();
float opacity = 0.25f;
if (viewCubeRect.contains(physicalMousePos)) {
opacity = 1.0f;
}
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glClear(GL_DEPTH_BUFFER_BIT);
QMatrix4x4 viewCubeProjection;
viewCubeProjection.ortho(-2, 2, -2, 2, -10, 10);
drawViewCube(viewCubeProjection, viewMatrix, opacity);
drawAxes(simpleShader, simpleShaderColorLoc, viewCubeProjection, viewMatrix);
glDisable(GL_BLEND);
}
void ViewCube::createFaceTextures()
{
QStringList labels = {"FRONT", "BACK", "TOP", "BOTTOM", "RIGHT", "LEFT"};
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]);
m_faceTextures[i] = new QOpenGLTexture(image.mirrored(false, true));
m_faceTextures[i]->setMinificationFilter(QOpenGLTexture::Linear);
m_faceTextures[i]->setMagnificationFilter(QOpenGLTexture::Linear);
}
}
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;
GLfloat vertices[] = {
// positions // texture Coords
// Front face
-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
-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
-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
-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
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
-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,
};
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::drawViewCube(const QMatrix4x4& projection, const QMatrix4x4& view, float opacity)
{
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);
m_textureShaderProgram->setUniformValue("opacity", opacity);
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);
// X-axis (red)
simpleShader->setUniformValue(colorLoc, QVector4D(1.0f, 0.0f, 0.0f, 1.0f));
glDrawArrays(GL_LINES, 0, 2);
// Y-axis (green)
simpleShader->setUniformValue(colorLoc, QVector4D(0.0f, 1.0f, 0.0f, 1.0f));
glDrawArrays(GL_LINES, 2, 2);
// Z-axis (blue)
simpleShader->setUniformValue(colorLoc, QVector4D(0.0f, 0.0f, 1.0f, 1.0f));
glDrawArrays(GL_LINES, 4, 2);
glLineWidth(1.0f);
}