src/glrenderer.cpp

changeset 1437
1a77c6156db7
parent 1436
241d3e452b32
child 1438
988b6563d47d
equal deleted inserted replaced
1436:241d3e452b32 1437:1a77c6156db7
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()
244 m_compiler->initialize(); 180 m_compiler->initialize();
245 initializeAxes(); 181 initializeAxes();
246 initializeLighting(); 182 initializeLighting();
247 m_initialized = true; 183 m_initialized = true;
248 // Now that GL is initialized, we can reset angles. 184 // Now that GL is initialized, we can reset angles.
249 resetAllAngles(); 185 resetAngles();
250 } 186 }
251 187
252 void gl::Renderer::initializeLighting() 188 void gl::Renderer::initializeLighting()
253 { 189 {
254 GLfloat materialShininess[] = {5.0}; 190 GLfloat materialShininess[] = {5.0};
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 */
376 if (config::lighting() and not m_isDrawingSelectionScene) 310 if (config::lighting() and not m_isDrawingSelectionScene)
377 glEnable(GL_LIGHTING); 311 glEnable(GL_LIGHTING);
378 else 312 else
379 glDisable(GL_LIGHTING); 313 glDisable(GL_LIGHTING);
380 314
381 if (camera() != gl::FreeCamera) 315 if (not m_cameraInfo.isModelview())
382 { 316 {
383 glMatrixMode (GL_PROJECTION); 317 glMatrixMode (GL_PROJECTION);
384 glPushMatrix(); 318 glPushMatrix();
385 glLoadIdentity(); 319 glLoadIdentity();
386 glMultMatrixf(currentCamera().realMatrix().constData()); 320 glMultMatrixf(currentCamera().realMatrix().constData());
561 overpaint(painter); 495 overpaint(painter);
562 } 496 }
563 497
564 void gl::Renderer::overpaint(QPainter &painter) 498 void gl::Renderer::overpaint(QPainter &painter)
565 { 499 {
566 // Draw a background for the selected camera
567 painter.setPen(thinBorderPen);
568 painter.setBrush(QBrush {QColor {0, 128, 160, 128}});
569 painter.drawRect(m_cameraIcons[static_cast<int>(camera())].hitRect);
570
571 // Draw the camera icons
572 for (const CameraIcon& info : m_cameraIcons)
573 {
574 // Don't draw the free camera icon when we can't use the free camera
575 if (info.camera == gl::FreeCamera and not freeCameraAllowed())
576 continue;
577
578 painter.drawPixmap(info.targetRect, info.image, info.sourceRect);
579 }
580
581 // Draw a label for the current camera in the bottom left corner 500 // Draw a label for the current camera in the bottom left corner
582 { 501 {
583 QFontMetrics metrics {QFont {}}; 502 QFontMetrics metrics {QFont {}};
584 int margin = 4; 503 int margin = 4;
585 painter.setPen(textPen()); 504 painter.setPen(textPen());
589 508
590 // ============================================================================= 509 // =============================================================================
591 // 510 //
592 void gl::Renderer::mouseReleaseEvent(QMouseEvent* event) 511 void gl::Renderer::mouseReleaseEvent(QMouseEvent* event)
593 { 512 {
594 bool wasLeft = (m_lastButtons & Qt::LeftButton) and not (event->buttons() & Qt::LeftButton); 513 ignore(event);
595 m_panning = false; 514 m_panning = false;
596
597 // Check if we selected a camera icon
598 if (wasLeft and not mouseHasMoved())
599 {
600 for (CameraIcon& info : m_cameraIcons)
601 {
602 if (info.targetRect.contains (event->pos()))
603 {
604 setCamera (info.camera);
605 break;
606 }
607 }
608 }
609
610 update(); 515 update();
611 m_totalMouseMove = 0; 516 m_totalMouseMove = 0;
612 } 517 }
613 518
614 // ============================================================================= 519 // =============================================================================
636 { 541 {
637 currentCamera().pan(xMove, yMove); 542 currentCamera().pan(xMove, yMove);
638 m_panning = true; 543 m_panning = true;
639 m_isCameraMoving = true; 544 m_isCameraMoving = true;
640 } 545 }
641 else if (left and camera() == gl::FreeCamera and (xMove != 0 or yMove != 0)) 546 else if (left and m_cameraInfo.isModelview() and (xMove != 0 or yMove != 0))
642 { 547 {
643 QQuaternion versor = QQuaternion::fromAxisAndAngle(yMove, xMove, 0, 0.6 * hypot(xMove, yMove)); 548 QQuaternion versor = QQuaternion::fromAxisAndAngle(yMove, xMove, 0, 0.6 * hypot(xMove, yMove));
644 m_rotation = versor * m_rotation; 549 m_rotation = versor * m_rotation;
645 m_isCameraMoving = true; 550 m_isCameraMoving = true;
646 } 551 }
688 // 593 //
689 void gl::Renderer::leaveEvent(QEvent*) 594 void gl::Renderer::leaveEvent(QEvent*)
690 { 595 {
691 m_toolTipTimer->stop(); 596 m_toolTipTimer->stop();
692 update(); 597 update();
693 }
694
695 // =============================================================================
696 //
697 void gl::Renderer::setCamera(gl::CameraType camera)
698 {
699 // The edit mode may forbid the free camera.
700 if (freeCameraAllowed() or camera != gl::FreeCamera)
701 {
702 m_camera = camera;
703 config::setCamera(static_cast<int>(camera));
704 }
705 } 598 }
706 599
707 /* 600 /*
708 * Resolves a pixel pointer to an RGB color. 601 * Resolves a pixel pointer to an RGB color.
709 * pixel[0..2] must be valid. 602 * pixel[0..2] must be valid.
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()

mercurial