--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/layers/axeslayer.cpp Sun Jun 26 21:00:06 2022 +0300 @@ -0,0 +1,162 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2020 Teemu Piippo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "gl/partrenderer.h" +#include <QPainter> +#include <QPainterPath> +#include "axeslayer.h" + +static constexpr char vertexShaderSource[] = R"( +#version 330 core + +layout (location = 0) in vec3 in_position; +layout (location = 1) in vec3 in_color; +uniform mat4 mvp; +smooth out vec3 ex_color; + +void main() +{ + gl_Position = mvp * vec4(in_position, 1.0); + ex_color = in_color; +} +)"; + +static constexpr char fragmentShaderSource[] = R"( +#version 330 core + +out vec4 color; +smooth in vec3 ex_color; + +void main(void) +{ + color = vec4(ex_color, 1); +} +)"; + +void AxesLayer::initializeGL() +{ + constexpr struct VertexType + { + glm::vec3 position; + glm::vec3 color; + } data[] = { + {{10000, 0, 0}, {1, 0, 0}}, + {{0, 0, 0}, {1, 0, 0}}, + {{-10000, 0, 0}, {0.5, 0, 0}}, + {{0, 0, 0}, {0.5, 0, 0}}, + {{0, 10000, 0}, {0, 1, 0}}, + {{0, 0, 0}, {0, 1, 0}}, + {{0, -10000, 0}, {0, 0.5, 0}}, + {{0, 0, 0}, {0, 0.5, 0}}, + {{0, 0, 10000}, {0, 0, 1}}, + {{0, 0, 0}, {0, 0, 1}}, + {{0, 0, -10000}, {0, 0, 0.5}}, + {{0, 0, 0}, {0, 0, 0.5}}, + }; + constexpr int stride = sizeof(VertexType); + this->shader.initialize( + ::vertexShaderSource, + ::fragmentShaderSource, + QOpenGLBuffer::StaticDraw, + { + GLAttributeSpec{ + .type = GL_FLOAT, + .offset = offsetof(VertexType, position), + .tuplesize = 3, + .stride = stride, + }, + { + .type = GL_FLOAT, + .offset = offsetof(VertexType, color), + .tuplesize = 3, + .stride = stride, + }, + }); + this->shader.bufferData(&data[0], countof(data), sizeof data[0]); +} + +void AxesLayer::overpaint(QPainter* painter) +{ + painter->save(); + QFont font; + font.setStyle(QFont::StyleItalic); + font.setBold(true); + painter->setFont(font); + QFontMetrics fontMetrics{font}; + const auto renderText = [&](const QString& text, const PointOnRectagle& intersection) + { + QPointF position = toQPointF(intersection.position); + const RectangleSide side = intersection.side; + switch (side) + { + case RectangleSide::Top: + position += QPointF{0, static_cast<qreal>(fontMetrics.ascent())}; + break; + case RectangleSide::Left: + break; + case RectangleSide::Bottom: + position += QPointF{0, static_cast<qreal>(-fontMetrics.descent())}; + break; + case RectangleSide::Right: + position += QPointF{static_cast<qreal>(-fontMetrics.horizontalAdvance(text)), 0}; + break; + } + drawBorderedText(painter, position, font, text); + }; + const QRectF box {QPointF{0, 0}, sizeToSizeF(this->renderer->size())}; + const QPointF p1 = this->renderer->modelToScreenCoordinates(glm::vec3{0, 0, 0}); + static const struct + { + QString text; + glm::vec3 direction; + } directions[] = + { + {"+x", {1, 0, 0}}, + {"-x", {-1, 0, 0}}, + {"+y", {0, 1, 0}}, + {"-y", {0, -1, 0}}, + {"+z", {0, 0, 1}}, + {"-z", {0, 0, -1}}, + }; + for (const auto& axis : directions) + { + const QPointF x_p = this->renderer->modelToScreenCoordinates(axis.direction); + const auto intersection = rayRectangleIntersection( + rayFromPoints(toVec2(p1), toVec2(x_p)), + box); + if (intersection.has_value()) + { + renderText(axis.text, *intersection); + } + } + painter->restore(); +} + +void AxesLayer::paintGL() +{ + glLineWidth(5); + glEnable(GL_LINE_SMOOTH); + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); + this->shader.draw(GL_LINES); + glDisable(GL_LINE_SMOOTH); +} + +void AxesLayer::mvpMatrixChanged(const glm::mat4& mvpMatrix) +{ + this->shader.setMvpMatrix(mvpMatrix); +}