src/glRenderer.cpp

changeset 1104
edddb9b0db9e
parent 1103
ac7db4c076c3
child 1105
4f4d219e527d
equal deleted inserted replaced
1103:ac7db4c076c3 1104:edddb9b0db9e
29 #include "colors.h" 29 #include "colors.h"
30 #include "mainwindow.h" 30 #include "mainwindow.h"
31 #include "miscallenous.h" 31 #include "miscallenous.h"
32 #include "editHistory.h" 32 #include "editHistory.h"
33 #include "dialogs.h" 33 #include "dialogs.h"
34 #include "messageLog.h"
35 #include "glCompiler.h" 34 #include "glCompiler.h"
36 #include "primitives.h" 35 #include "primitives.h"
37 #include "documentmanager.h" 36 #include "documentmanager.h"
38 #include "grid.h" 37 #include "grid.h"
39 38
71 QGLWidget {parent}, 70 QGLWidget {parent},
72 HierarchyElement {parent}, 71 HierarchyElement {parent},
73 m_model {model} 72 m_model {model}
74 { 73 {
75 m_camera = (Camera) m_config->camera(); 74 m_camera = (Camera) m_config->camera();
76 m_currentEditMode = AbstractEditMode::createByType (this, EditModeType::Select);
77 m_compiler = new GLCompiler (this); 75 m_compiler = new GLCompiler (this);
78 m_toolTipTimer = new QTimer (this); 76 m_toolTipTimer = new QTimer (this);
79 m_toolTipTimer->setSingleShot (true); 77 m_toolTipTimer->setSingleShot (true);
80 m_thinBorderPen = QPen (QColor (0, 0, 0, 208), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); 78 m_thinBorderPen = QPen (QColor (0, 0, 0, 208), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
81 m_thinBorderPen.setWidth (1); 79 m_thinBorderPen.setWidth (1);
87 // Init camera icons 85 // Init camera icons
88 for (Camera camera : iterateEnum<Camera>()) 86 for (Camera camera : iterateEnum<Camera>())
89 { 87 {
90 const char* cameraIconNames[EnumLimits<Camera>::Count] = 88 const char* cameraIconNames[EnumLimits<Camera>::Count] =
91 { 89 {
92 "camera-top", "camera-front", "camera-left", 90 "camera-top", "camera-front", "camera-left",
93 "camera-bottom", "camera-back", "camera-right", 91 "camera-bottom", "camera-back", "camera-right",
94 "camera-free" 92 "camera-free"
95 }; 93 };
96 94
97 CameraIcon* info = &m_cameraIcons[camera]; 95 CameraIcon* info = &m_cameraIcons[camera];
98 info->image = GetIcon (cameraIconNames[camera]); 96 info->image = GetIcon (cameraIconNames[camera]);
99 info->camera = camera; 97 info->camera = camera;
106 // 104 //
107 GLRenderer::~GLRenderer() 105 GLRenderer::~GLRenderer()
108 { 106 {
109 m_compiler->setRenderer (nullptr); 107 m_compiler->setRenderer (nullptr);
110 delete m_compiler; 108 delete m_compiler;
111 delete m_currentEditMode;
112 glDeleteBuffers (1, &m_axesVbo); 109 glDeleteBuffers (1, &m_axesVbo);
113 glDeleteBuffers (1, &m_axesColorVbo); 110 glDeleteBuffers (1, &m_axesColorVbo);
114 } 111 }
115 112
116 // ============================================================================= 113 // =============================================================================
357 { 354 {
358 m_needZoomToFit = false; 355 m_needZoomToFit = false;
359 zoomAllToFit(); 356 zoomAllToFit();
360 } 357 }
361 358
359 m_virtualWidth = zoom();
360 m_virtualHeight = (m_height * m_virtualWidth) / m_width;
361
362 if (m_config->drawWireframe() and not m_isDrawingSelectionScene) 362 if (m_config->drawWireframe() and not m_isDrawingSelectionScene)
363 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 363 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
364 364
365 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 365 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
366 glEnable(GL_DEPTH_TEST); 366 glEnable(GL_DEPTH_TEST);
569 linepen.setWidth(2); 569 linepen.setWidth(2);
570 linepen.setColor(luma(m_backgroundColor) < 40 ? Qt::white : Qt::black); 570 linepen.setColor(luma(m_backgroundColor) < 40 ? Qt::white : Qt::black);
571 return linepen; 571 return linepen;
572 } 572 }
573 573
574 // ============================================================================= 574 bool GLRenderer::freeCameraAllowed() const
575 // 575 {
576 return true;
577 }
578
576 void GLRenderer::paintEvent(QPaintEvent*) 579 void GLRenderer::paintEvent(QPaintEvent*)
577 { 580 {
578 makeCurrent(); 581 makeCurrent();
579 m_virtualWidth = zoom();
580 m_virtualHeight = (m_height * m_virtualWidth) / m_width;
581 initGLData(); 582 initGLData();
582 drawGLScene(); 583 drawGLScene();
584
585 if (isDrawingSelectionScene())
586 return;
587
583 QPainter painter {this}; 588 QPainter painter {this};
584 QFontMetrics metrics {QFont {}};
585 painter.setRenderHint(QPainter::Antialiasing); 589 painter.setRenderHint(QPainter::Antialiasing);
586 590 overpaint(painter);
587 // If we wish to only draw the brick, stop here 591 }
588 if (isDrawOnly() or m_isDrawingSelectionScene) 592
589 return; 593 void GLRenderer::overpaint(QPainter &painter)
590 594 {
591 #ifndef RELEASE 595 // Draw a background for the selected camera
592 { 596 painter.setPen(m_thinBorderPen);
593 QString text = format("Rotation: %1\nPanning: (%2, %3), Zoom: %4", 597 painter.setBrush(QBrush {QColor {0, 128, 160, 128}});
594 m_rotationMatrix, panning(X), panning(Y), zoom()); 598 painter.drawRect(m_cameraIcons[camera()].hitRect);
595 QRect textSize = metrics.boundingRect(0, 0, m_width, m_height, Qt::AlignCenter, text); 599
600 // Draw the camera icons
601 for (const CameraIcon& info : m_cameraIcons)
602 {
603 // Don't draw the free camera icon when we can't use the free camera
604 if (&info == &m_cameraIcons[FreeCamera] and not freeCameraAllowed())
605 continue;
606
607 painter.drawPixmap(info.targetRect, info.image, info.sourceRect);
608 }
609
610 // Tool tips
611 if (m_drawToolTip)
612 {
613 if (not m_cameraIcons[m_toolTipCamera].targetRect.contains (m_mousePosition))
614 m_drawToolTip = false;
615 else
616 QToolTip::showText(m_globalpos, currentCameraName());
617 }
618
619 // Draw a label for the current camera in the bottom left corner
620 {
621 QFontMetrics metrics {QFont {}};
622 int margin = 4;
596 painter.setPen(textPen()); 623 painter.setPen(textPen());
597 painter.drawText((width() - textSize.width()) / 2, height() - textSize.height(), textSize.width(), 624 painter.drawText(QPoint {margin, height() - margin - metrics.descent()}, currentCameraName());
598 textSize.height(), Qt::AlignCenter, text); 625
599 } 626 // Also render triangle count.
600 #endif 627 if (m_model)
601 628 {
602 if (camera() != FreeCamera) 629 QPoint renderPoint = {margin, height() - margin - metrics.height() - metrics.descent()};
603 { 630 painter.drawText(renderPoint, format("△ %1", m_model->triangleCount()));
604 // Paint the coordinates onto the screen.
605 QString text = format(tr("X: %1, Y: %2, Z: %3"), m_position3D[X], m_position3D[Y], m_position3D[Z]);
606 QFontMetrics metrics {font()};
607 QRect textSize = metrics.boundingRect (0, 0, m_width, m_height, Qt::AlignCenter, text);
608 painter.setPen(textPen());
609 painter.drawText(m_width - textSize.width(), m_height - 16,
610 textSize.width(), textSize.height(), Qt::AlignCenter, text);
611 }
612
613 {
614 // Draw edit mode HUD
615 m_currentEditMode->render(painter);
616
617 // Draw a background for the selected camera
618 painter.setPen(m_thinBorderPen);
619 painter.setBrush(QBrush {QColor {0, 128, 160, 128}});
620 painter.drawRect(m_cameraIcons[camera()].hitRect);
621
622 // Draw the camera icons
623 for (CameraIcon& info : m_cameraIcons)
624 {
625 // Don't draw the free camera icon when we can't use the free camera
626 if (&info == &m_cameraIcons[FreeCamera] and not m_currentEditMode->allowFreeCamera())
627 continue;
628
629 painter.drawPixmap(info.targetRect, info.image, info.sourceRect);
630 }
631
632 // Draw a label for the current camera in the bottom left corner
633 {
634 int margin = 4;
635 painter.setPen(textPen());
636 painter.drawText(QPoint {margin, height() - margin - metrics.descent()}, currentCameraName());
637
638 // Also render triangle count.
639 if (m_model)
640 {
641 QPoint renderPoint = {margin, height() - margin - metrics.height() - metrics.descent()};
642 painter.drawText(renderPoint, format("△ %1", m_model->triangleCount()));
643 }
644 }
645
646 // Tool tips
647 if (m_drawToolTip)
648 {
649 if (not m_cameraIcons[m_toolTipCamera].targetRect.contains (m_mousePosition))
650 m_drawToolTip = false;
651 else
652 QToolTip::showText(m_globalpos, currentCameraName());
653 }
654 }
655
656 // Message log
657 if (m_window->messageLog())
658 {
659 int y = 0;
660 int margin = 2;
661 QColor penColor = textPen().color();
662
663 for (const MessageManager::Line& line : m_window->messageLog()->getLines())
664 {
665 penColor.setAlphaF(line.alpha);
666 painter.setPen(penColor);
667 painter.drawText(QPoint {margin, y + margin + metrics.ascent()}, line.text);
668 y += metrics.height();
669 } 631 }
670 } 632 }
671 } 633 }
672 634
673 // ============================================================================= 635 // =============================================================================
693 painter.drawText (pos.x(), pos.y() - 8, pos3d.toString (true)); 655 painter.drawText (pos.x(), pos.y() - 8, pos3d.toString (true));
694 } 656 }
695 657
696 // ============================================================================= 658 // =============================================================================
697 // 659 //
698 void GLRenderer::mouseReleaseEvent(QMouseEvent* ev) 660 void GLRenderer::mouseReleaseEvent(QMouseEvent* event)
699 { 661 {
700 bool wasLeft = (m_lastButtons & Qt::LeftButton) and not (ev->buttons() & Qt::LeftButton); 662 bool wasLeft = (m_lastButtons & Qt::LeftButton) and not (event->buttons() & Qt::LeftButton);
701 Qt::MouseButtons releasedbuttons = m_lastButtons & ~ev->buttons();
702 m_panning = false; 663 m_panning = false;
703 664
704 if (wasLeft) 665 // Check if we selected a camera icon
705 { 666 if (wasLeft and not mouseHasMoved())
706 // Check if we selected a camera icon 667 {
707 if (not mouseHasMoved()) 668 for (CameraIcon& info : m_cameraIcons)
708 { 669 {
709 for (CameraIcon& info : m_cameraIcons) 670 if (info.targetRect.contains (event->pos()))
710 { 671 {
711 if (info.targetRect.contains (ev->pos())) 672 setCamera (info.camera);
712 { 673 break;
713 setCamera (info.camera);
714 goto end;
715 }
716 } 674 }
717 } 675 }
718 } 676 }
719 677
720 if (not isDrawOnly())
721 {
722 AbstractEditMode::MouseEventData data;
723 data.ev = ev;
724 data.mouseMoved = mouseHasMoved();
725 data.keymods = m_currentKeyboardModifiers;
726 data.releasedButtons = releasedbuttons;
727
728 if (m_currentEditMode->mouseReleased (data))
729 goto end;
730 }
731
732 end:
733 update(); 678 update();
734 m_totalMouseMove = 0; 679 m_totalMouseMove = 0;
735 } 680 }
736 681
737 // ============================================================================= 682 // =============================================================================
738 // 683 //
739 void GLRenderer::mousePressEvent(QMouseEvent* event) 684 void GLRenderer::mousePressEvent(QMouseEvent* event)
740 { 685 {
686 m_lastButtons = event->buttons();
741 m_totalMouseMove = 0; 687 m_totalMouseMove = 0;
742 m_lastButtons = event->buttons();
743
744 if (m_currentEditMode->mousePressed(event))
745 event->accept();
746 } 688 }
747 689
748 // ============================================================================= 690 // =============================================================================
749 // 691 //
750 void GLRenderer::mouseMoveEvent(QMouseEvent* event) 692 void GLRenderer::mouseMoveEvent(QMouseEvent* event)
752 int xMove = event->x() - m_mousePosition.x(); 694 int xMove = event->x() - m_mousePosition.x();
753 int yMove = event->y() - m_mousePosition.y(); 695 int yMove = event->y() - m_mousePosition.y();
754 m_totalMouseMove += qAbs(xMove) + qAbs(yMove); 696 m_totalMouseMove += qAbs(xMove) + qAbs(yMove);
755 m_isCameraMoving = false; 697 m_isCameraMoving = false;
756 698
757 if (not m_currentEditMode->mouseMoved (event)) 699 bool left = event->buttons() & Qt::LeftButton;
758 { 700 bool mid = event->buttons() & Qt::MidButton;
759 bool left = event->buttons() & Qt::LeftButton; 701 bool shift = event->modifiers() & Qt::ShiftModifier;
760 bool mid = event->buttons() & Qt::MidButton; 702
761 bool shift = event->modifiers() & Qt::ShiftModifier; 703 if (mid or (left and shift))
762 704 {
763 if (mid or (left and shift)) 705 panning(X) += 0.03f * xMove * (zoom() / 7.5f);
764 { 706 panning(Y) -= 0.03f * yMove * (zoom() / 7.5f);
765 panning(X) += 0.03f * xMove * (zoom() / 7.5f); 707 m_panning = true;
766 panning(Y) -= 0.03f * yMove * (zoom() / 7.5f); 708 m_isCameraMoving = true;
767 m_panning = true; 709 }
768 m_isCameraMoving = true; 710 else if (left and camera() == FreeCamera and (xMove != 0 or yMove != 0))
769 } 711 {
770 else if (left and camera() == FreeCamera and (xMove != 0 or yMove != 0)) 712 // Apply current rotation input to the rotation matrix
771 { 713 // ref: https://forums.ldraw.org/thread-22006-post-24426.html#pid24426
772 // Apply current rotation input to the rotation matrix 714 glPushMatrix();
773 // ref: https://forums.ldraw.org/thread-22006-post-24426.html#pid24426 715 glLoadIdentity();
774 glPushMatrix(); 716 // 0.6 is an arbitrary rotation sensitivity scalar
775 glLoadIdentity(); 717 glRotatef(0.6 * hypot(xMove, yMove), yMove, xMove, 0);
776 // 0.6 is an arbitrary rotation sensitivity scalar 718 glMultMatrixf(m_rotationMatrix.constData());
777 glRotatef(0.6 * hypot(xMove, yMove), yMove, xMove, 0); 719 glGetFloatv(GL_MODELVIEW_MATRIX, m_rotationMatrix.data());
778 glMultMatrixf(m_rotationMatrix.constData()); 720 glPopMatrix();
779 glGetFloatv(GL_MODELVIEW_MATRIX, m_rotationMatrix.data()); 721 m_isCameraMoving = true;
780 glPopMatrix();
781 m_isCameraMoving = true;
782 }
783 } 722 }
784 723
785 // Start the tool tip timer 724 // Start the tool tip timer
786 if (not m_drawToolTip) 725 if (not m_drawToolTip)
787 m_toolTipTimer->start (500); 726 m_toolTipTimer->start (500);
789 // Update 2d position 728 // Update 2d position
790 m_mousePosition = event->pos(); 729 m_mousePosition = event->pos();
791 m_globalpos = event->globalPos(); 730 m_globalpos = event->globalPos();
792 m_mousePositionF = event->localPos(); 731 m_mousePositionF = event->localPos();
793 732
794 // Calculate 3d position of the cursor
795 m_position3D = (camera() != FreeCamera) ? convert2dTo3d (m_mousePosition, true) : Origin;
796
797 highlightCursorObject(); 733 highlightCursorObject();
798 update(); 734 update();
799 event->accept(); 735 event->accept();
800 } 736 }
801 737
809 // ============================================================================= 745 // =============================================================================
810 // 746 //
811 void GLRenderer::keyReleaseEvent(QKeyEvent* event) 747 void GLRenderer::keyReleaseEvent(QKeyEvent* event)
812 { 748 {
813 m_currentKeyboardModifiers = event->modifiers(); 749 m_currentKeyboardModifiers = event->modifiers();
814 m_currentEditMode->keyReleased(event);
815 update(); 750 update();
816 } 751 }
817 752
818 // ============================================================================= 753 // =============================================================================
819 // 754 //
846 // ============================================================================= 781 // =============================================================================
847 // 782 //
848 void GLRenderer::setCamera(Camera camera) 783 void GLRenderer::setCamera(Camera camera)
849 { 784 {
850 // The edit mode may forbid the free camera. 785 // The edit mode may forbid the free camera.
851 if (m_currentEditMode->allowFreeCamera() or camera != FreeCamera) 786 if (freeCameraAllowed() or camera != FreeCamera)
852 { 787 {
853 m_camera = camera; 788 m_camera = camera;
854 m_config->setCamera(int {camera}); 789 m_config->setCamera(int {camera});
855 } 790 }
856 } 791 }
967 return object; 902 return object;
968 } 903 }
969 904
970 // ============================================================================= 905 // =============================================================================
971 // 906 //
972 void GLRenderer::setEditMode(EditModeType a)
973 {
974 if (m_currentEditMode and m_currentEditMode->type() == a)
975 return;
976
977 delete m_currentEditMode;
978 m_currentEditMode = AbstractEditMode::createByType(this, a);
979
980 // If we cannot use the free camera, use the top one instead.
981 if (camera() == FreeCamera and not m_currentEditMode->allowFreeCamera())
982 setCamera(TopCamera);
983
984 m_window->updateEditModeActions();
985 update();
986 }
987
988 // =============================================================================
989 //
990 EditModeType GLRenderer::currentEditModeType() const
991 {
992 return m_currentEditMode->type();
993 }
994
995 // =============================================================================
996 //
997 void GLRenderer::setPicking(bool value) 907 void GLRenderer::setPicking(bool value)
998 { 908 {
999 m_isDrawingSelectionScene = value; 909 m_isDrawingSelectionScene = value;
1000 setBackground(); 910 setBackground();
1001 911
1235 zoomToFit(); 1145 zoomToFit();
1236 } 1146 }
1237 1147
1238 // ============================================================================= 1148 // =============================================================================
1239 // 1149 //
1240 void GLRenderer::mouseDoubleClickEvent (QMouseEvent* ev)
1241 {
1242 if (m_currentEditMode->mouseDoubleClicked (ev))
1243 ev->accept();
1244 }
1245
1246 // =============================================================================
1247 //
1248 void GLRenderer::highlightCursorObject() 1150 void GLRenderer::highlightCursorObject()
1249 { 1151 {
1250 if (not m_config->highlightObjectBelowCursor() and objectAtCursor() == nullptr) 1152 if (not m_config->highlightObjectBelowCursor() and objectAtCursor() == nullptr)
1251 return; 1153 return;
1252 1154
1288 1190
1289 void GLRenderer::dragEnterEvent (QDragEnterEvent* ev) 1191 void GLRenderer::dragEnterEvent (QDragEnterEvent* ev)
1290 { 1192 {
1291 if (m_window and ev->source() == m_window->getPrimitivesTree() and m_window->getPrimitivesTree()->currentItem()) 1193 if (m_window and ev->source() == m_window->getPrimitivesTree() and m_window->getPrimitivesTree()->currentItem())
1292 ev->acceptProposedAction(); 1194 ev->acceptProposedAction();
1293 }
1294
1295 void GLRenderer::dropEvent (QDropEvent* ev)
1296 {
1297 if (m_window and ev->source() == m_window->getPrimitivesTree())
1298 {
1299 PrimitiveTreeItem* item = static_cast<PrimitiveTreeItem*> (m_window->getPrimitivesTree()->currentItem());
1300 QString primitiveName = item->primitive()->name;
1301 LDSubfileReference* ref = currentDocument()->emplaceAt<LDSubfileReference>(m_window->suggestInsertPoint());
1302 ref->setFileInfo (m_documents->getDocumentByName (primitiveName));
1303 currentDocument()->addToSelection(ref);
1304 m_window->buildObjectList();
1305 refresh();
1306 ev->acceptProposedAction();
1307 }
1308 }
1309
1310 Vertex const& GLRenderer::position3D() const
1311 {
1312 return m_position3D;
1313 } 1195 }
1314 1196
1315 const CameraInfo& GLRenderer::cameraInfo (Camera camera) const 1197 const CameraInfo& GLRenderer::cameraInfo (Camera camera) const
1316 { 1198 {
1317 if (valueInEnum<Camera>(camera)) 1199 if (valueInEnum<Camera>(camera))
1370 1252
1371 double& GLRenderer::zoom() 1253 double& GLRenderer::zoom()
1372 { 1254 {
1373 return m_zoom[camera()]; 1255 return m_zoom[camera()];
1374 } 1256 }
1257
1258 const QGenericMatrix<4, 4, GLfloat>& GLRenderer::rotationMatrix() const
1259 {
1260 return m_rotationMatrix;
1261 }
1262
1263 bool GLRenderer::isDrawingSelectionScene() const
1264 {
1265 return m_isDrawingSelectionScene;
1266 }
1267
1268 Qt::MouseButtons GLRenderer::lastButtons() const
1269 {
1270 return m_lastButtons;
1271 }

mercurial