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); |
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); |
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)) |