src/layers/axeslayer.cpp

changeset 263
59b6027b9843
parent 259
c27612f0eac0
child 264
76a025db4948
--- /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);
+}

mercurial