refactor: Migrate ViewportWidget to shader-based OpenGL rendering (FFP disabled)

Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
This commit is contained in:
2026-02-15 13:03:37 -07:00
parent af121ce6eb
commit 0f43715c6b
5 changed files with 223 additions and 146 deletions

View File

@@ -22,6 +22,8 @@
#include <QParallelAnimationGroup> #include <QParallelAnimationGroup>
#include <cmath> #include <cmath>
#include <QtMath> #include <QtMath>
#include <QOpenGLShaderProgram>
#include <QVector>
ViewportWidget::ViewportWidget(QWidget *parent) ViewportWidget::ViewportWidget(QWidget *parent)
: QOpenGLWidget(parent) : QOpenGLWidget(parent)
@@ -45,6 +47,12 @@ ViewportWidget::ViewportWidget(QWidget *parent)
ViewportWidget::~ViewportWidget() ViewportWidget::~ViewportWidget()
{ {
makeCurrent();
delete m_shaderProgram;
m_vbo.destroy();
m_vao.destroy();
doneCurrent();
delete m_viewCube; delete m_viewCube;
delete m_sketchGrid; delete m_sketchGrid;
delete m_featureBrowser; delete m_featureBrowser;
@@ -60,6 +68,21 @@ void ViewportWidget::initializeGL()
{ {
initializeOpenGLFunctions(); initializeOpenGLFunctions();
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
initShaders();
m_vao.create();
QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
m_vbo.create();
m_vbo.bind();
m_vbo.allocate(nullptr, 0); // Allocate when drawing
// Position attribute
m_shaderProgram->enableAttributeArray(0);
m_shaderProgram->setAttributeBuffer(0, GL_FLOAT, 0, 3, 0);
m_vbo.release();
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
m_viewCube->initializeGL(); m_viewCube->initializeGL();
m_sketchGrid->initializeGL(); m_sketchGrid->initializeGL();
@@ -71,30 +94,34 @@ void ViewportWidget::paintGL()
glViewport(0, 0, width(), height()); glViewport(0, 0, width(), height());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (!m_shaderProgram || !m_shaderProgram->isLinked()) {
return;
}
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
QMatrix4x4 model = m_camera->modelViewMatrix(); QMatrix4x4 model = m_camera->modelViewMatrix();
m_shaderProgram->bind();
m_shaderProgram->setUniformValue(m_projMatrixLoc, projection);
m_shaderProgram->setUniformValue(m_mvMatrixLoc, model);
// For simplicity, we'll use a fixed-function pipeline style for drawing. QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
// In a real app, this would use shaders.
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(projection.constData());
glMatrixMode(GL_MODELVIEW); // Sketch grid rendering - temporarily disabled as it uses the fixed-function pipeline
glLoadMatrixf(model.constData()); // if (m_isSelectingPlane) {
// if (m_highlightedPlane != SketchPlane::NONE) {
// m_sketchGrid->paintGL(static_cast<SketchGrid::SketchPlane>(m_highlightedPlane), projection, model);
// }
// }
// if (m_currentPlane != SketchPlane::NONE) {
// m_sketchGrid->paintGL(static_cast<SketchGrid::SketchPlane>(m_currentPlane), projection, model);
// }
if (m_isSelectingPlane) { if (m_isSelectingPlane) {
if (m_highlightedPlane != SketchPlane::NONE) {
m_sketchGrid->paintGL(static_cast<SketchGrid::SketchPlane>(m_highlightedPlane), projection, model);
}
drawSelectionPlanes(); drawSelectionPlanes();
} }
if (m_currentPlane != SketchPlane::NONE) {
m_sketchGrid->paintGL(static_cast<SketchGrid::SketchPlane>(m_currentPlane), projection, model);
}
if (m_document) { if (m_document) {
for (Feature* feature : m_document->features()) { for (Feature* feature : m_document->features()) {
if (auto sketch = dynamic_cast<SketchFeature*>(feature)) { if (auto sketch = dynamic_cast<SketchFeature*>(feature)) {
@@ -103,66 +130,67 @@ void ViewportWidget::paintGL()
} }
} }
QVector<GLfloat> vertices;
if (m_isSnappingOrigin) { if (m_isSnappingOrigin) {
const float rectSize = 0.0075f * -m_camera->zoom(); const float rectSize = 0.0075f * -m_camera->zoom();
glColor4f(1.0, 1.0, 0.0, 0.5f); if (m_currentPlane == SketchPlane::XY) {
vertices << -rectSize << 0 << -rectSize << rectSize << 0 << -rectSize;
vertices << rectSize << 0 << -rectSize << rectSize << 0 << rectSize;
vertices << rectSize << 0 << rectSize << -rectSize << 0 << rectSize;
vertices << -rectSize << 0 << rectSize << -rectSize << 0 << -rectSize;
} else if (m_currentPlane == SketchPlane::XZ) {
vertices << -rectSize << -rectSize << 0 << rectSize << -rectSize << 0;
vertices << rectSize << -rectSize << 0 << rectSize << rectSize << 0;
vertices << rectSize << rectSize << 0 << -rectSize << rectSize << 0;
vertices << -rectSize << rectSize << 0 << -rectSize << -rectSize << 0;
} else if (m_currentPlane == SketchPlane::YZ) {
vertices << 0 << -rectSize << -rectSize << 0 << rectSize << -rectSize;
vertices << 0 << rectSize << -rectSize << 0 << rectSize << rectSize;
vertices << 0 << rectSize << rectSize << 0 << -rectSize << rectSize;
vertices << 0 << -rectSize << rectSize << 0 << -rectSize << -rectSize;
}
m_shaderProgram->setUniformValue(m_colorLoc, QVector4D(1.0f, 1.0f, 0.0f, 0.5f));
m_vbo.bind();
m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBegin(GL_LINE_LOOP); glDrawArrays(GL_LINES, 0, vertices.size() / 3);
if (m_currentPlane == SketchPlane::XY) {
glVertex3f(-rectSize, 0, -rectSize);
glVertex3f( rectSize, 0, -rectSize);
glVertex3f( rectSize, 0, rectSize);
glVertex3f(-rectSize, 0, rectSize);
} else if (m_currentPlane == SketchPlane::XZ) {
glVertex3f(-rectSize, -rectSize, 0);
glVertex3f( rectSize, -rectSize, 0);
glVertex3f( rectSize, rectSize, 0);
glVertex3f(-rectSize, rectSize, 0);
} else if (m_currentPlane == SketchPlane::YZ) {
glVertex3f(0, -rectSize, -rectSize);
glVertex3f(0, rectSize, -rectSize);
glVertex3f(0, rectSize, rectSize);
glVertex3f(0, -rectSize, rectSize);
}
glEnd();
glDisable(GL_BLEND); glDisable(GL_BLEND);
} else if (m_isSnappingVertex) { } else if (m_isSnappingVertex) {
const float rectSize = 0.0075f * -m_camera->zoom(); const float rectSize = 0.0075f * -m_camera->zoom();
glColor4f(1.0, 1.0, 0.0, 0.5f); const auto& v = m_snapVertex;
if (m_currentPlane == SketchPlane::XY) {
vertices << v.X() - rectSize << v.Y() << v.Z() - rectSize << v.X() + rectSize << v.Y() << v.Z() - rectSize;
vertices << v.X() + rectSize << v.Y() << v.Z() - rectSize << v.X() + rectSize << v.Y() << v.Z() + rectSize;
vertices << v.X() + rectSize << v.Y() << v.Z() + rectSize << v.X() - rectSize << v.Y() << v.Z() + rectSize;
vertices << v.X() - rectSize << v.Y() << v.Z() + rectSize << v.X() - rectSize << v.Y() << v.Z() - rectSize;
} else if (m_currentPlane == SketchPlane::XZ) {
vertices << v.X() - rectSize << v.Y() - rectSize << v.Z() << v.X() + rectSize << v.Y() - rectSize << v.Z();
vertices << v.X() + rectSize << v.Y() - rectSize << v.Z() << v.X() + rectSize << v.Y() + rectSize << v.Z();
vertices << v.X() + rectSize << v.Y() + rectSize << v.Z() << v.X() - rectSize << v.Y() + rectSize << v.Z();
vertices << v.X() - rectSize << v.Y() + rectSize << v.Z() << v.X() - rectSize << v.Y() - rectSize << v.Z();
} else if (m_currentPlane == SketchPlane::YZ) {
vertices << v.X() << v.Y() - rectSize << v.Z() - rectSize << v.X() << v.Y() + rectSize << v.Z() - rectSize;
vertices << v.X() << v.Y() + rectSize << v.Z() - rectSize << v.X() << v.Y() + rectSize << v.Z() + rectSize;
vertices << v.X() << v.Y() + rectSize << v.Z() + rectSize << v.X() << v.Y() - rectSize << v.Z() + rectSize;
vertices << v.X() << v.Y() - rectSize << v.Z() + rectSize << v.X() << v.Y() - rectSize << v.Z() - rectSize;
}
m_shaderProgram->setUniformValue(m_colorLoc, QVector4D(1.0f, 1.0f, 0.0f, 0.5f));
m_vbo.bind();
m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBegin(GL_LINE_LOOP); glDrawArrays(GL_LINES, 0, vertices.size() / 3);
if (m_currentPlane == SketchPlane::XY) {
glVertex3f(m_snapVertex.X() - rectSize, m_snapVertex.Y(), m_snapVertex.Z() - rectSize);
glVertex3f(m_snapVertex.X() + rectSize, m_snapVertex.Y(), m_snapVertex.Z() - rectSize);
glVertex3f(m_snapVertex.X() + rectSize, m_snapVertex.Y(), m_snapVertex.Z() + rectSize);
glVertex3f(m_snapVertex.X() - rectSize, m_snapVertex.Y(), m_snapVertex.Z() + rectSize);
} else if (m_currentPlane == SketchPlane::XZ) {
glVertex3f(m_snapVertex.X() - rectSize, m_snapVertex.Y() - rectSize, m_snapVertex.Z());
glVertex3f(m_snapVertex.X() + rectSize, m_snapVertex.Y() - rectSize, m_snapVertex.Z());
glVertex3f(m_snapVertex.X() + rectSize, m_snapVertex.Y() + rectSize, m_snapVertex.Z());
glVertex3f(m_snapVertex.X() - rectSize, m_snapVertex.Y() + rectSize, m_snapVertex.Z());
} else if (m_currentPlane == SketchPlane::YZ) {
glVertex3f(m_snapVertex.X(), m_snapVertex.Y() - rectSize, m_snapVertex.Z() - rectSize);
glVertex3f(m_snapVertex.X(), m_snapVertex.Y() + rectSize, m_snapVertex.Z() - rectSize);
glVertex3f(m_snapVertex.X(), m_snapVertex.Y() + rectSize, m_snapVertex.Z() + rectSize);
glVertex3f(m_snapVertex.X(), m_snapVertex.Y() - rectSize, m_snapVertex.Z() + rectSize);
}
glEnd();
glDisable(GL_BLEND); glDisable(GL_BLEND);
} }
if (m_isDefiningLine && m_activeTool == static_cast<int>(ApplicationController::ToolType::Line)) { if (m_isDefiningLine && m_activeTool == static_cast<int>(ApplicationController::ToolType::Line)) {
vertices.clear();
QVector3D worldPos = unproject(m_currentMousePos, m_currentPlane); QVector3D worldPos = unproject(m_currentMousePos, m_currentPlane);
if (m_isSnappingOrigin) { if (m_isSnappingOrigin) {
worldPos.setX(0); worldPos.setX(0); worldPos.setY(0); worldPos.setZ(0);
worldPos.setY(0);
worldPos.setZ(0);
} else if (m_isSnappingVertex) { } else if (m_isSnappingVertex) {
worldPos.setX(m_snapVertex.X()); worldPos.setX(m_snapVertex.X()); worldPos.setY(m_snapVertex.Y()); worldPos.setZ(m_snapVertex.Z());
worldPos.setY(m_snapVertex.Y());
worldPos.setZ(m_snapVertex.Z());
} else if (m_isSnappingHorizontal) { } else if (m_isSnappingHorizontal) {
if (m_currentPlane == SketchPlane::XY) worldPos.setZ(m_firstLinePoint.Z()); if (m_currentPlane == SketchPlane::XY) worldPos.setZ(m_firstLinePoint.Z());
else if (m_currentPlane == SketchPlane::XZ) worldPos.setY(m_firstLinePoint.Y()); else if (m_currentPlane == SketchPlane::XZ) worldPos.setY(m_firstLinePoint.Y());
@@ -172,56 +200,58 @@ void ViewportWidget::paintGL()
else if (m_currentPlane == SketchPlane::XZ) worldPos.setX(m_firstLinePoint.X()); else if (m_currentPlane == SketchPlane::XZ) worldPos.setX(m_firstLinePoint.X());
else if (m_currentPlane == SketchPlane::YZ) worldPos.setY(m_firstLinePoint.Y()); else if (m_currentPlane == SketchPlane::YZ) worldPos.setY(m_firstLinePoint.Y());
} }
glBegin(GL_LINES); vertices << m_firstLinePoint.X() << m_firstLinePoint.Y() << m_firstLinePoint.Z();
glColor3f(1.0, 1.0, 0.0); vertices << worldPos.x() << worldPos.y() << worldPos.z();
glVertex3d(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z());
glVertex3d(worldPos.x(), worldPos.y(), worldPos.z()); m_shaderProgram->setUniformValue(m_colorLoc, QVector4D(1.0f, 1.0f, 0.0f, 1.0f));
glEnd(); m_vbo.bind();
m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
glDrawArrays(GL_LINES, 0, 2);
if (m_isSnappingHorizontal || m_isSnappingVertical) { if (m_isSnappingHorizontal || m_isSnappingVertical) {
vertices.clear();
QVector3D startPos(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z()); QVector3D startPos(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z());
QVector3D midPoint = (startPos + worldPos) / 2.0; QVector3D midPoint = (startPos + worldPos) / 2.0;
const float indicatorSize = 0.02f * -m_camera->zoom(); const float indicatorSize = 0.02f * -m_camera->zoom();
const float indicatorOffset = 0.02f * -m_camera->zoom(); const float indicatorOffset = 0.02f * -m_camera->zoom();
glColor3f(1.0, 1.0, 0.0);
glBegin(GL_LINES);
if (m_isSnappingHorizontal) { if (m_isSnappingHorizontal) {
if (m_currentPlane == SketchPlane::XY) { if (m_currentPlane == SketchPlane::XY) {
glVertex3f(midPoint.x() - indicatorSize, midPoint.y(), midPoint.z() + indicatorOffset); vertices << midPoint.x() - indicatorSize << midPoint.y() << midPoint.z() + indicatorOffset;
glVertex3f(midPoint.x() + indicatorSize, midPoint.y(), midPoint.z() + indicatorOffset); vertices << midPoint.x() + indicatorSize << midPoint.y() << midPoint.z() + indicatorOffset;
} else if (m_currentPlane == SketchPlane::XZ) { } else if (m_currentPlane == SketchPlane::XZ) {
glVertex3f(midPoint.x() - indicatorSize, midPoint.y() + indicatorOffset, midPoint.z()); vertices << midPoint.x() - indicatorSize << midPoint.y() + indicatorOffset << midPoint.z();
glVertex3f(midPoint.x() + indicatorSize, midPoint.y() + indicatorOffset, midPoint.z()); vertices << midPoint.x() + indicatorSize << midPoint.y() + indicatorOffset << midPoint.z();
} else if (m_currentPlane == SketchPlane::YZ) { } else if (m_currentPlane == SketchPlane::YZ) {
glVertex3f(midPoint.x(), midPoint.y() - indicatorSize, midPoint.z() + indicatorOffset); vertices << midPoint.x() << midPoint.y() - indicatorSize << midPoint.z() + indicatorOffset;
glVertex3f(midPoint.x(), midPoint.y() + indicatorSize, midPoint.z() + indicatorOffset); vertices << midPoint.x() << midPoint.y() + indicatorSize << midPoint.z() + indicatorOffset;
} }
} else { // m_isSnappingVertical } else { // m_isSnappingVertical
if (m_currentPlane == SketchPlane::XY) { if (m_currentPlane == SketchPlane::XY) {
glVertex3f(midPoint.x() + indicatorOffset, midPoint.y(), midPoint.z() - indicatorSize); vertices << midPoint.x() + indicatorOffset << midPoint.y() << midPoint.z() - indicatorSize;
glVertex3f(midPoint.x() + indicatorOffset, midPoint.y(), midPoint.z() + indicatorSize); vertices << midPoint.x() + indicatorOffset << midPoint.y() << midPoint.z() + indicatorSize;
} else if (m_currentPlane == SketchPlane::XZ) { } else if (m_currentPlane == SketchPlane::XZ) {
glVertex3f(midPoint.x() + indicatorOffset, midPoint.y() - indicatorSize, midPoint.z()); vertices << midPoint.x() + indicatorOffset << midPoint.y() - indicatorSize << midPoint.z();
glVertex3f(midPoint.x() + indicatorOffset, midPoint.y() + indicatorSize, midPoint.z()); vertices << midPoint.x() + indicatorOffset << midPoint.y() + indicatorSize << midPoint.z();
} else if (m_currentPlane == SketchPlane::YZ) { } else if (m_currentPlane == SketchPlane::YZ) {
glVertex3f(midPoint.x(), midPoint.y() + indicatorOffset, midPoint.z() - indicatorSize); vertices << midPoint.x() << midPoint.y() + indicatorOffset << midPoint.z() - indicatorSize;
glVertex3f(midPoint.x(), midPoint.y() + indicatorOffset, midPoint.z() + indicatorSize); vertices << midPoint.x() << midPoint.y() + indicatorOffset << midPoint.z() + indicatorSize;
} }
} }
glEnd(); m_vbo.bind();
m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
glDrawArrays(GL_LINES, 0, 2);
} }
} }
// View cube rendering m_shaderProgram->release();
QMatrix4x4 viewCubeModel;
viewCubeModel.rotate(m_camera->xRotation() / 16.0f, 1, 0, 0); // View cube rendering - temporarily disabled as it uses the fixed-function pipeline
viewCubeModel.rotate(m_camera->yRotation() / 16.0f, 0, 1, 0); // QMatrix4x4 viewCubeModel;
m_viewCube->paintGL(viewCubeModel, width(), height()); // 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());
glViewport(0, 0, width(), height()); glViewport(0, 0, width(), height());
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
@@ -701,28 +731,61 @@ void ViewportWidget::drawSketch(const SketchFeature* sketch)
{ {
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glLineWidth(2.0f); glLineWidth(2.0f);
glColor3f(1.0, 1.0, 1.0);
glPointSize(5.0f); glPointSize(5.0f);
QVector<GLfloat> lineVertices;
QVector<GLfloat> pointVertices;
for (const auto& obj : sketch->objects()) { for (const auto& obj : sketch->objects()) {
if (obj->type() == SketchObject::ObjectType::Line) { if (obj->type() == SketchObject::ObjectType::Line) {
auto line = static_cast<const SketchLine*>(obj); auto line = static_cast<const SketchLine*>(obj);
const auto& start = line->startPoint(); const auto& start = line->startPoint();
const auto& end = line->endPoint(); const auto& end = line->endPoint();
glBegin(GL_LINES); lineVertices << start.X() << start.Y() << start.Z();
glVertex3d(start.X(), start.Y(), start.Z()); lineVertices << end.X() << end.Y() << end.Z();
glVertex3d(end.X(), end.Y(), end.Z());
glEnd();
glBegin(GL_POINTS); pointVertices << start.X() << start.Y() << start.Z();
glVertex3d(start.X(), start.Y(), start.Z()); pointVertices << end.X() << end.Y() << end.Z();
glVertex3d(end.X(), end.Y(), end.Z());
glEnd();
} }
} }
m_shaderProgram->setUniformValue(m_colorLoc, QVector4D(1.0f, 1.0f, 1.0f, 1.0f));
m_vbo.bind();
if (!lineVertices.isEmpty()) {
m_vbo.allocate(lineVertices.constData(), lineVertices.size() * sizeof(GLfloat));
glDrawArrays(GL_LINES, 0, lineVertices.size() / 3);
}
if (!pointVertices.isEmpty()) {
m_vbo.allocate(pointVertices.constData(), pointVertices.size() * sizeof(GLfloat));
glDrawArrays(GL_POINTS, 0, pointVertices.size() / 3);
}
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
} }
void ViewportWidget::initShaders()
{
m_shaderProgram = new QOpenGLShaderProgram(this);
if (!m_shaderProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/simple.vert")) {
qCritical() << "Vertex shader compilation failed:" << m_shaderProgram->log();
return;
}
if (!m_shaderProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/simple.frag")) {
qCritical() << "Fragment shader compilation failed:" << m_shaderProgram->log();
return;
}
if (!m_shaderProgram->link()) {
qCritical() << "Shader program linking failed:" << m_shaderProgram->log();
return;
}
m_projMatrixLoc = m_shaderProgram->uniformLocation("projectionMatrix");
m_mvMatrixLoc = m_shaderProgram->uniformLocation("modelViewMatrix");
m_colorLoc = m_shaderProgram->uniformLocation("objectColor");
}
void ViewportWidget::drawSelectionPlanes() void ViewportWidget::drawSelectionPlanes()
{ {
const float planeSize = 5.0f; const float planeSize = 5.0f;
@@ -734,61 +797,36 @@ void ViewportWidget::drawSelectionPlanes()
glLineWidth(2.0f); glLineWidth(2.0f);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
// Draw back to front for proper blending m_vbo.bind();
QVector<GLfloat> vertices;
// XY Plane (Top), normal is Y (green) auto drawPlane = [&](const QVector<GLfloat>& quadVerts, bool highlighted) {
glColor4f(1.0f, 1.0f, 0.0f, m_highlightedPlane == SketchPlane::XY ? 0.5f : 0.2f); // Draw fill
if (m_highlightedPlane == SketchPlane::XY) { if (highlighted) {
glBegin(GL_QUADS); m_shaderProgram->setUniformValue(m_colorLoc, QVector4D(1.0f, 1.0f, 0.0f, 0.5f));
glVertex3f(planeOffset, 0, planeOffset); m_vbo.allocate(quadVerts.constData(), quadVerts.size() * sizeof(GLfloat));
glVertex3f(planeOffset + planeSize, 0, planeOffset); glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glVertex3f(planeOffset + planeSize, 0, planeOffset + planeSize); }
glVertex3f(planeOffset, 0, planeOffset + planeSize); // Draw outline
glEnd(); m_shaderProgram->setUniformValue(m_colorLoc, QVector4D(1.0f, 1.0f, 0.0f, 1.0f));
} m_vbo.allocate(quadVerts.constData(), quadVerts.size() * sizeof(GLfloat));
glColor4f(1.0f, 1.0f, 0.0f, 1.0f); glDrawArrays(GL_LINE_LOOP, 0, 4);
glBegin(GL_LINE_LOOP); };
glVertex3f(planeOffset, 0, planeOffset);
glVertex3f(planeOffset + planeSize, 0, planeOffset);
glVertex3f(planeOffset + planeSize, 0, planeOffset + planeSize);
glVertex3f(planeOffset, 0, planeOffset + planeSize);
glEnd();
// XZ Plane (Front), normal is Z (blue) // XY Plane (Top)
glColor4f(1.0f, 1.0f, 0.0f, m_highlightedPlane == SketchPlane::XZ ? 0.5f : 0.2f); QVector<GLfloat> xyQuad = { planeOffset, 0, planeOffset, planeOffset + planeSize, 0, planeOffset,
if (m_highlightedPlane == SketchPlane::XZ) { planeOffset + planeSize, 0, planeOffset + planeSize, planeOffset, 0, planeOffset + planeSize };
glBegin(GL_QUADS); drawPlane(xyQuad, m_highlightedPlane == SketchPlane::XY);
glVertex3f(planeOffset, planeOffset, 0);
glVertex3f(planeOffset + planeSize, planeOffset, 0);
glVertex3f(planeOffset + planeSize, planeOffset + planeSize, 0);
glVertex3f(planeOffset, planeOffset + planeSize, 0);
glEnd();
}
glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
glBegin(GL_LINE_LOOP);
glVertex3f(planeOffset, planeOffset, 0);
glVertex3f(planeOffset + planeSize, planeOffset, 0);
glVertex3f(planeOffset + planeSize, planeOffset + planeSize, 0);
glVertex3f(planeOffset, planeOffset + planeSize, 0);
glEnd();
// YZ Plane (Right), normal is X (red) // XZ Plane (Front)
glColor4f(1.0f, 1.0f, 0.0f, m_highlightedPlane == SketchPlane::YZ ? 0.5f : 0.2f); QVector<GLfloat> xzQuad = { planeOffset, planeOffset, 0, planeOffset + planeSize, planeOffset, 0,
if (m_highlightedPlane == SketchPlane::YZ) { planeOffset + planeSize, planeOffset + planeSize, 0, planeOffset, planeOffset + planeSize, 0 };
glBegin(GL_QUADS); drawPlane(xzQuad, m_highlightedPlane == SketchPlane::XZ);
glVertex3f(0, planeOffset, planeOffset);
glVertex3f(0, planeOffset + planeSize, planeOffset); // YZ Plane (Right)
glVertex3f(0, planeOffset + planeSize, planeOffset + planeSize); QVector<GLfloat> yzQuad = { 0, planeOffset, planeOffset, 0, planeOffset + planeSize, planeOffset,
glVertex3f(0, planeOffset, planeOffset + planeSize); 0, planeOffset + planeSize, planeOffset + planeSize, 0, planeOffset, planeOffset + planeSize };
glEnd(); drawPlane(yzQuad, m_highlightedPlane == SketchPlane::YZ);
}
glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
glBegin(GL_LINE_LOOP);
glVertex3f(0, planeOffset, planeOffset);
glVertex3f(0, planeOffset + planeSize, planeOffset);
glVertex3f(0, planeOffset + planeSize, planeOffset + planeSize);
glVertex3f(0, planeOffset, planeOffset + planeSize);
glEnd();
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);

View File

@@ -9,6 +9,9 @@
#include <QRect> #include <QRect>
#include <gp_Pnt.hxx> #include <gp_Pnt.hxx>
#include <QMap> #include <QMap>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLBuffer>
class QSvgRenderer; class QSvgRenderer;
class ViewCube; class ViewCube;
@@ -56,6 +59,7 @@ protected:
void keyPressEvent(QKeyEvent *event) override; void keyPressEvent(QKeyEvent *event) override;
private: private:
void initShaders();
QVector3D project(const QVector3D& worldCoord, const QMatrix4x4& modelView, const QMatrix4x4& projection, const QRect& viewport); QVector3D project(const QVector3D& worldCoord, const QMatrix4x4& modelView, const QMatrix4x4& projection, const QRect& viewport);
QVector3D unproject(const QPoint& screenPos, SketchPlane plane); QVector3D unproject(const QPoint& screenPos, SketchPlane plane);
void drawAxisLabels(QPainter& painter, const QMatrix4x4& modelView, const QMatrix4x4& projection); void drawAxisLabels(QPainter& painter, const QMatrix4x4& modelView, const QMatrix4x4& projection);
@@ -64,6 +68,14 @@ private:
ViewportWidget::SketchPlane checkPlaneSelection(const QPoint& screenPos); ViewportWidget::SketchPlane checkPlaneSelection(const QPoint& screenPos);
QMatrix4x4 projection; QMatrix4x4 projection;
QOpenGLShaderProgram* m_shaderProgram = nullptr;
QOpenGLVertexArrayObject m_vao;
QOpenGLBuffer m_vbo;
// Shader uniform locations
int m_projMatrixLoc = -1;
int m_mvMatrixLoc = -1;
int m_colorLoc = -1;
Camera* m_camera = nullptr; Camera* m_camera = nullptr;
ViewCube* m_viewCube; ViewCube* m_viewCube;
SketchGrid* m_sketchGrid = nullptr; SketchGrid* m_sketchGrid = nullptr;

6
src/shaders/shaders.qrc Normal file
View File

@@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/shaders">
<file>simple.vert</file>
<file>simple.frag</file>
</qresource>
</RCC>

10
src/shaders/simple.frag Normal file
View File

@@ -0,0 +1,10 @@
#version 330 core
out vec4 FragColor;
uniform vec4 objectColor;
void main()
{
FragColor = objectColor;
}

11
src/shaders/simple.vert Normal file
View File

@@ -0,0 +1,11 @@
#version 330 core
layout (location = 0) in vec3 aPos;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
void main()
{
gl_Position = projectionMatrix * modelViewMatrix * vec4(aPos, 1.0);
}