#include "ViewportWidget.h" #include "ViewCube.h" #include "SketchGrid.h" #include #include #include #include #include #include ViewportWidget::ViewportWidget(QWidget *parent) : QOpenGLWidget(parent) { m_viewCube = new ViewCube(); m_sketchGrid = new SketchGrid(); } ViewportWidget::~ViewportWidget() { delete m_viewCube; delete m_sketchGrid; } void ViewportWidget::initializeGL() { initializeOpenGLFunctions(); glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glEnable(GL_DEPTH_TEST); m_viewCube->initializeGL(); m_sketchGrid->initializeGL(); } void ViewportWidget::paintGL() { // Main scene rendering glViewport(0, 0, width(), height()); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); QMatrix4x4 model; model.translate(panX, panY, zoom); model.rotate(xRot / 16.0f, 1, 0, 0); model.rotate(yRot / 16.0f, 0, 1, 0); // For simplicity, we'll use a fixed-function pipeline style for drawing. // In a real app, this would use shaders. glMatrixMode(GL_PROJECTION); glLoadMatrixf(projection.constData()); glMatrixMode(GL_MODELVIEW); glLoadMatrixf(model.constData()); if (m_currentPlane != SketchPlane::NONE) { m_sketchGrid->paintGL(static_cast(m_currentPlane), projection, model); } // View cube rendering QMatrix4x4 viewCubeModel; viewCubeModel.rotate(xRot / 16.0f, 1, 0, 0); viewCubeModel.rotate(yRot / 16.0f, 0, 1, 0); m_viewCube->paintGL(viewCubeModel, width(), height()); glViewport(0, 0, width(), height()); if (m_currentPlane != SketchPlane::NONE) { QPainter painter(this); drawAxisLabels(painter, model, projection); painter.end(); } } void ViewportWidget::resizeGL(int w, int h) { projection.setToIdentity(); projection.perspective(45.0f, w / float(h), 0.01f, 100.0f); } void ViewportWidget::mousePressEvent(QMouseEvent *event) { lastPos = event->pos(); } void ViewportWidget::mouseMoveEvent(QMouseEvent *event) { int dx = event->pos().x() - lastPos.x(); int dy = event->pos().y() - lastPos.y(); if (event->buttons() & Qt::MiddleButton) { if (QApplication::keyboardModifiers() & Qt::ShiftModifier) { // Pan panX += dx / 100.0f; panY -= dy / 100.0f; } else { // Rotate xRot += 8 * dy; yRot += 8 * dx; } } lastPos = event->pos(); update(); } void ViewportWidget::wheelEvent(QWheelEvent *event) { QPoint numDegrees = event->angleDelta() / 8; if (!numDegrees.isNull()) { zoom += numDegrees.y() / 5.0f; } update(); } void ViewportWidget::startSketch(SketchPlane plane) { m_currentPlane = plane; panX = 0; panY = 0; zoom = -20.0f; // Zoom out to see the grid switch (plane) { case SketchPlane::XY: // Top view xRot = -90 * 16; yRot = 0; break; case SketchPlane::XZ: // Front view xRot = 0; yRot = 0; break; case SketchPlane::YZ: // Right view xRot = 0; yRot = 90 * 16; break; case SketchPlane::NONE: break; } update(); } QVector3D ViewportWidget::project(const QVector3D& worldCoord, const QMatrix4x4& modelView, const QMatrix4x4& projection, const QRect& viewport) { QVector4D clipCoord = projection * modelView * QVector4D(worldCoord, 1.0); if (qFuzzyCompare(clipCoord.w(), 0.0f)) { return QVector3D(-1, -1, -1); } QVector3D ndc(clipCoord.x() / clipCoord.w(), clipCoord.y() / clipCoord.w(), clipCoord.z() / clipCoord.w()); float winX = viewport.x() + viewport.width() * (ndc.x() + 1.0) / 2.0; float winY = viewport.y() + viewport.height() * (1.0 - (ndc.y() + 1.0) / 2.0); // Y is inverted return QVector3D(winX, winY, (ndc.z() + 1.0) / 2.0); } void ViewportWidget::drawAxisLabels(QPainter& painter, const QMatrix4x4& modelView, const QMatrix4x4& projection) { painter.setPen(Qt::white); painter.setFont(QFont("Arial", 10)); const int range = 50; const int step = 5; auto drawLabelsForAxis = [&](int axis_idx) { for (int i = -range; i <= range; i += step) { if (i == 0) continue; QVector3D worldCoord; worldCoord[axis_idx] = i; QVector3D screenPos = project(worldCoord, modelView, projection, rect()); if (screenPos.z() < 1.0f) { // Not clipped painter.drawText(screenPos.toPoint(), QString::number(i)); } } }; if (m_currentPlane == SketchPlane::XY) { drawLabelsForAxis(0); // X drawLabelsForAxis(1); // Y } else if (m_currentPlane == SketchPlane::XZ) { drawLabelsForAxis(0); // X drawLabelsForAxis(2); // Z } else if (m_currentPlane == SketchPlane::YZ) { drawLabelsForAxis(1); // Y drawLabelsForAxis(2); // Z } }