Files
unnamed-cad-software/src/SketchGrid.cpp
2026-02-17 13:58:58 -07:00

196 lines
6.2 KiB
C++

#include "SketchGrid.h"
#include "ViewportWidget.h"
#include "Camera.h"
#include <QOpenGLContext>
#include <QOpenGLExtraFunctions>
#include <QOpenGLShaderProgram>
#include <QPainter>
#include <QVector>
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<GLfloat> minorLines;
QVector<GLfloat> majorLines;
int numLines = gridSize / minorIncrement;
for (int i = -numLines; i <= numLines; ++i) {
if (i == 0)
continue;
float pos = i * minorIncrement;
QVector<GLfloat>& 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<GLfloat> 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
}
}