32 #include "glcompiler.h" |
32 #include "glcompiler.h" |
33 #include "primitives.h" |
33 #include "primitives.h" |
34 #include "documentmanager.h" |
34 #include "documentmanager.h" |
35 #include "grid.h" |
35 #include "grid.h" |
36 |
36 |
|
37 static GLCamera const cameraTemplates[7] = { |
|
38 {"Top camera", {gl::topCameraMatrix, X, Z, false, false, false}}, |
|
39 {"Front camera", {gl::frontCameraMatrix, X, Y, false, true, false}}, |
|
40 {"Left camera", {gl::leftCameraMatrix, Z, Y, true, true, false}}, |
|
41 {"Bottom camera", {gl::bottomCameraMatrix, X, Z, false, true, true}}, |
|
42 {"Back camera", {gl::backCameraMatrix, X, Y, true, true, true}}, |
|
43 {"Right camera", {gl::rightCameraMatrix, Z, Y, false, true, true}}, |
|
44 {"Free camera", GLCamera::FreeCamera}, |
|
45 }; |
|
46 |
37 /* |
47 /* |
38 * Constructs a GL renderer. |
48 * Constructs a GL renderer. |
39 */ |
49 */ |
40 gl::Renderer::Renderer(const Model* model, QWidget* parent) : |
50 gl::Renderer::Renderer(const Model* model, CameraType cameraType, QWidget* parent) : |
41 QGLWidget {parent}, |
51 QGLWidget {parent}, |
42 HierarchyElement {parent}, |
52 HierarchyElement {parent}, |
43 m_model {model}, |
53 m_model {model}, |
44 m_cameras { |
54 m_camera {cameraType}, |
45 {"Top camera", {topCameraMatrix, X, Z, false, false, false}}, // top |
55 m_cameraInfo {::cameraTemplates[cameraType]} |
46 {"Front camera", {frontCameraMatrix, X, Y, false, true, false}}, // front |
|
47 {"Left camera", {leftCameraMatrix, Z, Y, true, true, false}}, // left |
|
48 {"Bottom camera", {bottomCameraMatrix, X, Z, false, true, true}}, // bottom |
|
49 {"Back camera", {backCameraMatrix, X, Y, true, true, true}}, // back |
|
50 {"Right camera", {rightCameraMatrix, Z, Y, false, true, true}}, // right |
|
51 {"Free camera", GLCamera::FreeCamera}, // free |
|
52 } |
|
53 { |
56 { |
54 Q_ASSERT(model != nullptr); |
57 Q_ASSERT(model != nullptr); |
55 m_camera = (gl::CameraType) config::camera(); |
|
56 m_compiler = new gl::Compiler (this); |
58 m_compiler = new gl::Compiler (this); |
57 m_toolTipTimer = new QTimer (this); |
59 m_toolTipTimer = new QTimer (this); |
58 m_toolTipTimer->setSingleShot (true); |
60 m_toolTipTimer->setSingleShot (true); |
59 setAcceptDrops (true); |
61 setAcceptDrops (true); |
60 connect (m_toolTipTimer, SIGNAL (timeout()), this, SLOT (showCameraIconTooltip())); |
62 connect (m_toolTipTimer, SIGNAL (timeout()), this, SLOT (showCameraIconTooltip())); |
61 resetAllAngles(); |
63 resetAngles(); |
62 m_needZoomToFit = true; |
64 m_needZoomToFit = true; |
63 |
|
64 // Init camera icons |
|
65 for (gl::CameraType camera : iterateEnum<gl::CameraType>()) |
|
66 { |
|
67 const char* cameraIconNames[EnumLimits<gl::CameraType>::Count] = |
|
68 { |
|
69 "camera-top", "camera-front", "camera-left", |
|
70 "camera-bottom", "camera-back", "camera-right", |
|
71 "camera-free" |
|
72 }; |
|
73 |
|
74 CameraIcon* info = &m_cameraIcons[static_cast<int>(camera)]; |
|
75 info->image = MainWindow::getIcon (cameraIconNames[static_cast<int>(camera)]); |
|
76 info->camera = camera; |
|
77 } |
|
78 |
65 |
79 connect( |
66 connect( |
80 this->m_compiler, |
67 this->m_compiler, |
81 &gl::Compiler::sceneChanged, |
68 &gl::Compiler::sceneChanged, |
82 this, |
69 this, |
83 qOverload<>(&gl::Renderer::update) |
70 qOverload<>(&gl::Renderer::update) |
84 ); |
71 ); |
85 |
|
86 calcCameraIcons(); |
|
87 } |
72 } |
88 |
73 |
89 /* |
74 /* |
90 * Destructs the GL renderer. |
75 * Destructs the GL renderer. |
91 */ |
76 */ |
106 m_axesInitialized = false; |
91 m_axesInitialized = false; |
107 } |
92 } |
108 } |
93 } |
109 |
94 |
110 /* |
95 /* |
111 * Calculates the camera icon locations. |
|
112 */ |
|
113 void gl::Renderer::calcCameraIcons() |
|
114 { |
|
115 int i = 0; |
|
116 const int columns = 3; |
|
117 const int firstAtLastRow = countof(m_cameras) - (countof(m_cameras) % columns); |
|
118 |
|
119 for (CameraIcon& cameraIcon : m_cameraIcons) |
|
120 { |
|
121 int row = i / columns; |
|
122 int column = i % columns; |
|
123 |
|
124 // Do right-justifying on the last row. |
|
125 if (i >= firstAtLastRow) |
|
126 column += columns - (countof(m_cameras) % columns); |
|
127 |
|
128 int x1 = width() - 48 + (column * 16) - 1; |
|
129 int y1 = (row * 16) + 1; |
|
130 |
|
131 cameraIcon.sourceRect = {0, 0, 16, 16}; |
|
132 cameraIcon.targetRect = {x1, y1, 16, 16}; |
|
133 cameraIcon.hitRect = { |
|
134 cameraIcon.targetRect.x(), |
|
135 cameraIcon.targetRect.y(), |
|
136 cameraIcon.targetRect.width() + 1, |
|
137 cameraIcon.targetRect.height() + 1 |
|
138 }; |
|
139 |
|
140 ++i; |
|
141 } |
|
142 } |
|
143 |
|
144 /* |
|
145 * Returns the camera currently in use. |
96 * Returns the camera currently in use. |
146 */ |
97 */ |
147 GLCamera& gl::Renderer::currentCamera() |
98 GLCamera& gl::Renderer::currentCamera() |
148 { |
99 { |
149 return m_cameras[static_cast<int>(camera())]; |
100 return m_cameraInfo; |
150 } |
101 } |
151 |
102 |
152 /* |
103 /* |
153 * Returns the camera currently in use. |
104 * Returns the camera currently in use. |
154 */ |
105 */ |
155 const GLCamera& gl::Renderer::currentCamera() const |
106 const GLCamera& gl::Renderer::currentCamera() const |
156 { |
107 { |
157 return m_cameras[static_cast<int>(camera())]; |
108 return m_cameraInfo; |
158 } |
109 } |
159 |
110 |
160 /* |
111 /* |
161 * Prepares the GL context for rendering. |
112 * Prepares the GL context for rendering. |
162 */ |
113 */ |
205 m_rotation = QQuaternion::fromAxisAndAngle({1, 0, 0}, 30); |
156 m_rotation = QQuaternion::fromAxisAndAngle({1, 0, 0}, 30); |
206 m_rotation *= QQuaternion::fromAxisAndAngle({0, 1, 0}, 330); |
157 m_rotation *= QQuaternion::fromAxisAndAngle({0, 1, 0}, 330); |
207 } |
158 } |
208 currentCamera().setPanning(0, 0); |
159 currentCamera().setPanning(0, 0); |
209 needZoomToFit(); |
160 needZoomToFit(); |
210 } |
|
211 |
|
212 // ============================================================================= |
|
213 // |
|
214 void gl::Renderer::resetAllAngles() |
|
215 { |
|
216 gl::CameraType const oldCamera = camera(); |
|
217 |
|
218 for (gl::CameraType camera : iterateEnum<gl::CameraType>()) |
|
219 { |
|
220 setCamera(camera); |
|
221 resetAngles(); |
|
222 } |
|
223 |
|
224 setCamera(oldCamera); |
|
225 } |
161 } |
226 |
162 |
227 // ============================================================================= |
163 // ============================================================================= |
228 // |
164 // |
229 void gl::Renderer::initializeGL() |
165 void gl::Renderer::initializeGL() |
330 |
266 |
331 // ============================================================================= |
267 // ============================================================================= |
332 // |
268 // |
333 void gl::Renderer::resizeGL (int width, int height) |
269 void gl::Renderer::resizeGL (int width, int height) |
334 { |
270 { |
335 calcCameraIcons(); |
|
336 glViewport (0, 0, width, height); |
271 glViewport (0, 0, width, height); |
337 glMatrixMode (GL_PROJECTION); |
272 glMatrixMode (GL_PROJECTION); |
338 glLoadIdentity(); |
273 glLoadIdentity(); |
339 gluPerspective (45.0f, (double) width / (double) height, near, far); |
274 gluPerspective (45.0f, (double) width / (double) height, near, far); |
340 glMatrixMode (GL_MODELVIEW); |
275 glMatrixMode (GL_MODELVIEW); |
341 |
276 |
342 // Unfortunately Qt does not provide a resized() signal so we have to manually feed the information. |
277 // Unfortunately Qt does not provide a resized() signal so we have to manually feed the information. |
343 for (GLCamera& camera : m_cameras) |
278 m_cameraInfo.rendererResized(width, height); |
344 camera.rendererResized(width, height); |
|
345 } |
279 } |
346 |
280 |
347 /* |
281 /* |
348 * Pads a 3×3 matrix into a 4×4 one by adding cells from the identity matrix. |
282 * Pads a 3×3 matrix into a 4×4 one by adding cells from the identity matrix. |
349 */ |
283 */ |
825 glReadPixels(0, 0, width(), height(), GL_RGBA, GL_UNSIGNED_BYTE, pixelData.data()); |
718 glReadPixels(0, 0, width(), height(), GL_RGBA, GL_UNSIGNED_BYTE, pixelData.data()); |
826 |
719 |
827 // Prepare the image and return it. It appears that GL and Qt formats have red and blue swapped and the Y axis flipped. |
720 // Prepare the image and return it. It appears that GL and Qt formats have red and blue swapped and the Y axis flipped. |
828 QImage image {pixelData.constData(), width(), height(), QImage::Format_ARGB32}; |
721 QImage image {pixelData.constData(), width(), height(), QImage::Format_ARGB32}; |
829 return image.rgbSwapped().mirrored(); |
722 return image.rgbSwapped().mirrored(); |
830 } |
|
831 |
|
832 /* |
|
833 * Show a tooltip if the cursor is currently hovering over a camera icon. |
|
834 */ |
|
835 void gl::Renderer::showCameraIconTooltip() |
|
836 { |
|
837 for (CameraIcon & icon : m_cameraIcons) |
|
838 { |
|
839 if (icon.targetRect.contains (m_mousePosition)) |
|
840 { |
|
841 QToolTip::showText(m_globalpos, m_cameras[static_cast<int>(icon.camera)].name()); |
|
842 update(); |
|
843 break; |
|
844 } |
|
845 } |
|
846 } |
723 } |
847 |
724 |
848 // ============================================================================= |
725 // ============================================================================= |
849 // |
726 // |
850 void gl::Renderer::zoomToFit() |
727 void gl::Renderer::zoomToFit() |