#include "SketchGrid.h" #include "ViewportWidget.h" #include "Camera.h" #include #include #include #include #include namespace { struct GridParams { float minorIncrement; float majorIncrement; int gridSize; }; GridParams getGridParams(float distance) { if (distance > 500.0f) { return { 20.0f, 100.0f, 1000 }; } else if (distance > 250.0f) { return { 10.0f, 50.0f, 1000 }; } else if (distance > 50.0f) { return { 5.0f, 25.0f, 1000 }; } else if (distance > 10.0f) { return { 1.0f, 5.0f, 100 }; } else { // zoomed in return { 0.2f, 1.0f, 10 }; } } } // namespace SketchGrid::SketchGrid(ViewportWidget* viewport) : m_viewport(viewport) { } SketchGrid::~SketchGrid() { } void SketchGrid::initializeGL() { initializeOpenGLFunctions(); m_vao.create(); QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao); m_vbo.create(); m_vbo.bind(); m_vbo.allocate(nullptr, 0); // Allocate when drawing glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), nullptr); m_vbo.release(); } void SketchGrid::paintGL(SketchPlane plane, QOpenGLShaderProgram* shaderProgram, int colorLoc) { GLint previous_vao = 0; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &previous_vao); m_vao.bind(); glDisable(GL_DEPTH_TEST); drawGridLines(plane, shaderProgram, colorLoc); drawAxes(plane, shaderProgram, colorLoc); glEnable(GL_DEPTH_TEST); QOpenGLContext::currentContext()->extraFunctions()->glBindVertexArray(previous_vao); } void SketchGrid::drawGridLines(SketchPlane plane, QOpenGLShaderProgram* shaderProgram, int colorLoc) { auto params = getGridParams(-m_viewport->camera()->uiCameraDistance()); const float minorIncrement = params.minorIncrement; const int gridSize = params.gridSize; QVector minorLines; QVector majorLines; int numLines = gridSize / minorIncrement; for (int i = -numLines; i <= numLines; ++i) { if (i == 0) continue; float pos = i * minorIncrement; QVector& current_vector = (i % 5 == 0) ? majorLines : minorLines; if (plane == XY) { current_vector << pos << 0 << -gridSize << pos << 0 << gridSize; current_vector << -gridSize << 0 << pos << gridSize << 0 << pos; } else if (plane == XZ) { current_vector << pos << -gridSize << 0 << pos << gridSize << 0; current_vector << -gridSize << pos << 0 << gridSize << pos << 0; } else { // YZ current_vector << 0 << pos << -gridSize << 0 << pos << gridSize; current_vector << 0 << -gridSize << pos << 0 << gridSize << pos; } } m_vbo.bind(); // Draw minor lines shaderProgram->setUniformValue(colorLoc, QVector4D(0.4f, 0.4f, 0.4f, 1.0f)); glLineWidth(1.0f); m_vbo.allocate(minorLines.constData(), minorLines.size() * sizeof(GLfloat)); glDrawArrays(GL_LINES, 0, minorLines.size() / 3); // Draw major lines shaderProgram->setUniformValue(colorLoc, QVector4D(0.6f, 0.6f, 0.6f, 1.0f)); glLineWidth(1.0f); m_vbo.allocate(majorLines.constData(), majorLines.size() * sizeof(GLfloat)); glDrawArrays(GL_LINES, 0, majorLines.size() / 3); } void SketchGrid::drawAxes(SketchPlane plane, QOpenGLShaderProgram* shaderProgram, int colorLoc) { auto params = getGridParams(-m_viewport->camera()->uiCameraDistance()); const int axisLength = params.gridSize; QVector vertices; glLineWidth(2.0f); m_vbo.bind(); // X Axis (Red) if (plane == XY || plane == XZ) { vertices.clear(); vertices << -axisLength << 0 << 0 << axisLength << 0 << 0; shaderProgram->setUniformValue(colorLoc, QVector4D(1.0f, 0.0f, 0.0f, 1.0f)); m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat)); glDrawArrays(GL_LINES, 0, 2); } // Y Axis (Green) if (plane == XY || plane == YZ) { vertices.clear(); vertices << 0 << 0 << -axisLength << 0 << 0 << axisLength; shaderProgram->setUniformValue(colorLoc, QVector4D(0.0f, 1.0f, 0.0f, 1.0f)); m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat)); glDrawArrays(GL_LINES, 0, 2); } // Z Axis (Blue) if (plane == XZ || plane == YZ) { vertices.clear(); vertices << 0 << -axisLength << 0 << 0 << axisLength << 0; shaderProgram->setUniformValue(colorLoc, QVector4D(0.0f, 0.0f, 1.0f, 1.0f)); m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat)); glDrawArrays(GL_LINES, 0, 2); } // Origin dot glPointSize(5.0f); vertices.clear(); vertices << 0.0f << 0.0f << 0.0f; shaderProgram->setUniformValue(colorLoc, QVector4D(1.0f, 1.0f, 1.0f, 1.0f)); // White m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat)); glDrawArrays(GL_POINTS, 0, 1); } void SketchGrid::paintAxisLabels(QPainter& painter, SketchGrid::SketchPlane plane, const QMatrix4x4& modelView, const QMatrix4x4& projection) { painter.setPen(Qt::white); painter.setFont(QFont("Arial", 10)); auto params = getGridParams(-m_viewport->camera()->uiCameraDistance()); const float majorIncrement = params.majorIncrement; const int range = params.gridSize; auto drawLabelsForAxis = [&](int axis_idx) { int numLabels = range / majorIncrement; for (int i = -numLabels; i <= numLabels; ++i) { if (i == 0) continue; float val = i * majorIncrement; QVector3D worldCoord; worldCoord[axis_idx] = val; QVector3D screenPos = m_viewport->project(worldCoord, modelView, projection, m_viewport->rect()); if (screenPos.z() < 1.0f) { // Not clipped painter.drawText(screenPos.toPoint(), QString::number(val)); } } }; if (plane == SketchGrid::XY) { drawLabelsForAxis(0); // X drawLabelsForAxis(2); // Y } else if (plane == SketchGrid::XZ) { drawLabelsForAxis(0); // X drawLabelsForAxis(1); // Z } else if (plane == SketchGrid::YZ) { drawLabelsForAxis(1); // Y drawLabelsForAxis(2); // Z } }