1 /* |
|
2 * LDForge: LDraw parts authoring CAD |
|
3 * Copyright (C) 2020 Teemu Piippo |
|
4 * |
|
5 * This program is free software: you can redistribute it and/or modify |
|
6 * it under the terms of the GNU General Public License as published by |
|
7 * the Free Software Foundation, either version 3 of the License, or |
|
8 * (at your option) any later version. |
|
9 * |
|
10 * This program is distributed in the hope that it will be useful, |
|
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 * GNU General Public License for more details. |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License |
|
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
17 */ |
|
18 |
|
19 #include "gl/partrenderer.h" |
|
20 #include <QPainter> |
|
21 #include <QPainterPath> |
|
22 #include "axesprogram.h" |
|
23 |
|
24 static constexpr char vertexShaderSource[] = R"( |
|
25 #version 330 core |
|
26 |
|
27 layout (location = 0) in vec3 in_position; |
|
28 layout (location = 1) in vec3 in_color; |
|
29 uniform mat4 mvp; |
|
30 smooth out vec3 ex_color; |
|
31 |
|
32 void main() |
|
33 { |
|
34 gl_Position = mvp * vec4(in_position, 1.0); |
|
35 ex_color = in_color; |
|
36 } |
|
37 )"; |
|
38 |
|
39 static constexpr char fragmentShaderSource[] = R"( |
|
40 #version 330 core |
|
41 |
|
42 out vec4 color; |
|
43 smooth in vec3 ex_color; |
|
44 |
|
45 void main(void) |
|
46 { |
|
47 color = vec4(ex_color, 1); |
|
48 } |
|
49 )"; |
|
50 |
|
51 void AxesLayer::initializeGL() |
|
52 { |
|
53 constexpr struct VertexType |
|
54 { |
|
55 glm::vec3 position; |
|
56 glm::vec3 color; |
|
57 } data[] = { |
|
58 {{10000, 0, 0}, {1, 0, 0}}, |
|
59 {{0, 0, 0}, {1, 0, 0}}, |
|
60 {{-10000, 0, 0}, {0.5, 0, 0}}, |
|
61 {{0, 0, 0}, {0.5, 0, 0}}, |
|
62 {{0, 10000, 0}, {0, 1, 0}}, |
|
63 {{0, 0, 0}, {0, 1, 0}}, |
|
64 {{0, -10000, 0}, {0, 0.5, 0}}, |
|
65 {{0, 0, 0}, {0, 0.5, 0}}, |
|
66 {{0, 0, 10000}, {0, 0, 1}}, |
|
67 {{0, 0, 0}, {0, 0, 1}}, |
|
68 {{0, 0, -10000}, {0, 0, 0.5}}, |
|
69 {{0, 0, 0}, {0, 0, 0.5}}, |
|
70 }; |
|
71 constexpr int stride = sizeof(VertexType); |
|
72 this->shader.initialize( |
|
73 ::vertexShaderSource, |
|
74 ::fragmentShaderSource, |
|
75 QOpenGLBuffer::StaticDraw, |
|
76 { |
|
77 GLAttributeSpec{ |
|
78 .type = GL_FLOAT, |
|
79 .offset = offsetof(VertexType, position), |
|
80 .tuplesize = 3, |
|
81 .stride = stride, |
|
82 }, |
|
83 { |
|
84 .type = GL_FLOAT, |
|
85 .offset = offsetof(VertexType, color), |
|
86 .tuplesize = 3, |
|
87 .stride = stride, |
|
88 }, |
|
89 }); |
|
90 this->shader.bufferData(&data[0], countof(data), sizeof data[0]); |
|
91 } |
|
92 |
|
93 void AxesLayer::overpaint(QPainter* painter) |
|
94 { |
|
95 painter->save(); |
|
96 QFont font; |
|
97 font.setStyle(QFont::StyleItalic); |
|
98 font.setBold(true); |
|
99 painter->setFont(font); |
|
100 QFontMetrics fontMetrics{font}; |
|
101 const auto renderText = [&](const QString& text, const PointOnRectagle& intersection) |
|
102 { |
|
103 QPointF position = toQPointF(intersection.position); |
|
104 const RectangleSide side = intersection.side; |
|
105 switch (side) |
|
106 { |
|
107 case RectangleSide::Top: |
|
108 position += QPointF{0, static_cast<qreal>(fontMetrics.ascent())}; |
|
109 break; |
|
110 case RectangleSide::Left: |
|
111 break; |
|
112 case RectangleSide::Bottom: |
|
113 position += QPointF{0, static_cast<qreal>(-fontMetrics.descent())}; |
|
114 break; |
|
115 case RectangleSide::Right: |
|
116 position += QPointF{static_cast<qreal>(-fontMetrics.horizontalAdvance(text)), 0}; |
|
117 break; |
|
118 } |
|
119 drawBorderedText(painter, position, font, text); |
|
120 }; |
|
121 const QRectF box {QPointF{0, 0}, sizeToSizeF(this->renderer->size())}; |
|
122 const QPointF p1 = this->renderer->modelToScreenCoordinates(glm::vec3{0, 0, 0}); |
|
123 static const struct |
|
124 { |
|
125 QString text; |
|
126 glm::vec3 direction; |
|
127 } directions[] = |
|
128 { |
|
129 {"+x", {1, 0, 0}}, |
|
130 {"-x", {-1, 0, 0}}, |
|
131 {"+y", {0, 1, 0}}, |
|
132 {"-y", {0, -1, 0}}, |
|
133 {"+z", {0, 0, 1}}, |
|
134 {"-z", {0, 0, -1}}, |
|
135 }; |
|
136 for (const auto& axis : directions) |
|
137 { |
|
138 const QPointF x_p = this->renderer->modelToScreenCoordinates(axis.direction); |
|
139 const auto intersection = rayRectangleIntersection( |
|
140 rayFromPoints(toVec2(p1), toVec2(x_p)), |
|
141 box); |
|
142 if (intersection.has_value()) |
|
143 { |
|
144 renderText(axis.text, *intersection); |
|
145 } |
|
146 } |
|
147 painter->restore(); |
|
148 } |
|
149 |
|
150 void AxesLayer::paintGL() |
|
151 { |
|
152 glLineWidth(5); |
|
153 glEnable(GL_LINE_SMOOTH); |
|
154 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); |
|
155 this->shader.draw(GL_LINES); |
|
156 glDisable(GL_LINE_SMOOTH); |
|
157 } |
|
158 |
|
159 void AxesLayer::mvpMatrixChanged(const glm::mat4& mvpMatrix) |
|
160 { |
|
161 this->shader.setMvpMatrix(mvpMatrix); |
|
162 } |
|