184 lines
4.9 KiB
C++
184 lines
4.9 KiB
C++
#include "ViewportWidget.h"
|
|
#include "ViewCube.h"
|
|
#include "SketchGrid.h"
|
|
#include <QMouseEvent>
|
|
#include <QWheelEvent>
|
|
#include <QApplication>
|
|
#include <QPainter>
|
|
#include <QWheelEvent>
|
|
#include <QApplication>
|
|
|
|
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<SketchGrid::SketchPlane>(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
|
|
}
|
|
}
|