539 if (camera() == EFreeCamera) |
539 if (camera() == EFreeCamera) |
540 return Origin; |
540 return Origin; |
541 |
541 |
542 Vertex pos3d; |
542 Vertex pos3d; |
543 const LDFixedCamera* cam = &g_FixedCameras[camera()]; |
543 const LDFixedCamera* cam = &g_FixedCameras[camera()]; |
544 const Axis axisX = cam->localX; |
544 Axis axisX = cam->localX; |
545 const Axis axisY = cam->localY; |
545 Axis axisY = cam->localY; |
546 const int negXFac = cam->negatedX ? -1 : 1, |
546 int signX = cam->negatedX ? -1 : 1; |
547 negYFac = cam->negatedY ? -1 : 1; |
547 int signY = cam->negatedY ? -1 : 1; |
548 |
548 |
549 // Calculate cx and cy - these are the LDraw unit coords the cursor is at. |
549 // Calculate cx and cy - these are the LDraw unit coords the cursor is at. |
550 double cx = (-m_virtualWidth + ((2 * pos2d.x() * m_virtualWidth) / m_width) - panning (X)); |
550 double cx = (-m_virtualWidth + ((2 * pos2d.x() * m_virtualWidth) / m_width) - panning (X)); |
551 double cy = (m_virtualHeight - ((2 * pos2d.y() * m_virtualHeight) / m_height) - panning (Y)); |
551 double cy = (m_virtualHeight - ((2 * pos2d.y() * m_virtualHeight) / m_height) - panning (Y)); |
552 |
552 |
553 if (snap) |
553 if (snap) |
554 { |
554 { |
555 cx = Grid::Snap (cx, Grid::Coordinate); |
555 cx = snapToGrid (cx, Grid::Coordinate); |
556 cy = Grid::Snap (cy, Grid::Coordinate); |
556 cy = snapToGrid (cy, Grid::Coordinate); |
557 } |
557 } |
558 |
558 |
559 cx *= negXFac; |
559 cx *= signX; |
560 cy *= negYFac; |
560 cy *= signY; |
561 |
561 |
562 RoundToDecimals (cx, 4); |
562 roundToDecimals (cx, 4); |
563 RoundToDecimals (cy, 4); |
563 roundToDecimals (cy, 4); |
564 |
564 |
565 // Create the vertex from the coordinates |
565 // Create the vertex from the coordinates |
566 pos3d.setCoordinate (axisX, cx); |
566 pos3d.setCoordinate (axisX, cx); |
567 pos3d.setCoordinate (axisY, cy); |
567 pos3d.setCoordinate (axisY, cy); |
568 pos3d.setCoordinate ((Axis) (3 - axisX - axisY), getDepthValue()); |
568 pos3d.setCoordinate ((Axis) (3 - axisX - axisY), getDepthValue()); |
614 |
614 |
615 // ============================================================================= |
615 // ============================================================================= |
616 // |
616 // |
617 void GLRenderer::paintEvent (QPaintEvent*) |
617 void GLRenderer::paintEvent (QPaintEvent*) |
618 { |
618 { |
619 doMakeCurrent(); |
619 makeCurrent(); |
620 m_virtualWidth = zoom(); |
620 m_virtualWidth = zoom(); |
621 m_virtualHeight = (m_height * m_virtualWidth) / m_width; |
621 m_virtualHeight = (m_height * m_virtualWidth) / m_width; |
622 initGLData(); |
622 initGLData(); |
623 drawGLScene(); |
623 drawGLScene(); |
624 |
624 |
625 QPainter paint (this); |
625 QPainter painter (this); |
626 QFontMetrics metrics = QFontMetrics (QFont()); |
626 QFontMetrics metrics = QFontMetrics (QFont()); |
627 paint.setRenderHint (QPainter::HighQualityAntialiasing); |
627 painter.setRenderHint (QPainter::Antialiasing); |
|
628 painter.setRenderHint (QPainter::HighQualityAntialiasing); |
628 |
629 |
629 // If we wish to only draw the brick, stop here |
630 // If we wish to only draw the brick, stop here |
630 if (isDrawOnly()) |
631 if (isDrawOnly()) |
631 return; |
632 return; |
632 |
633 |
634 if (not isPicking()) |
635 if (not isPicking()) |
635 { |
636 { |
636 QString text = format ("Rotation: (%1°, %2°, %3°)\nPanning: (%4, %5), Zoom: %6", |
637 QString text = format ("Rotation: (%1°, %2°, %3°)\nPanning: (%4, %5), Zoom: %6", |
637 rotation(X), rotation(Y), rotation(Z), panning(X), panning(Y), zoom()); |
638 rotation(X), rotation(Y), rotation(Z), panning(X), panning(Y), zoom()); |
638 QRect textSize = metrics.boundingRect (0, 0, m_width, m_height, Qt::AlignCenter, text); |
639 QRect textSize = metrics.boundingRect (0, 0, m_width, m_height, Qt::AlignCenter, text); |
639 paint.setPen (textPen()); |
640 painter.setPen (textPen()); |
640 paint.drawText ((width() - textSize.width()) / 2, height() - textSize.height(), textSize.width(), |
641 painter.drawText ((width() - textSize.width()) / 2, height() - textSize.height(), textSize.width(), |
641 textSize.height(), Qt::AlignCenter, text); |
642 textSize.height(), Qt::AlignCenter, text); |
642 } |
643 } |
643 #endif |
644 #endif |
644 |
645 |
645 if (camera() != EFreeCamera and not isPicking()) |
646 if (camera() != EFreeCamera and not isPicking()) |
651 { |
652 { |
652 QPoint v0 = convert3dTo2d (currentDocumentData().overlays[camera()].v0); |
653 QPoint v0 = convert3dTo2d (currentDocumentData().overlays[camera()].v0); |
653 QPoint v1 = convert3dTo2d (currentDocumentData().overlays[camera()].v1); |
654 QPoint v1 = convert3dTo2d (currentDocumentData().overlays[camera()].v1); |
654 QRect targetRect (v0.x(), v0.y(), qAbs (v1.x() - v0.x()), qAbs (v1.y() - v0.y())); |
655 QRect targetRect (v0.x(), v0.y(), qAbs (v1.x() - v0.x()), qAbs (v1.y() - v0.y())); |
655 QRect sourceRect (0, 0, overlay.img->width(), overlay.img->height()); |
656 QRect sourceRect (0, 0, overlay.img->width(), overlay.img->height()); |
656 paint.drawImage (targetRect, *overlay.img, sourceRect); |
657 painter.drawImage (targetRect, *overlay.img, sourceRect); |
657 } |
658 } |
658 |
659 |
659 // Paint the coordinates onto the screen. |
660 // Paint the coordinates onto the screen. |
660 QString text = format (tr ("X: %1, Y: %2, Z: %3"), m_position3D[X], m_position3D[Y], m_position3D[Z]); |
661 QString text = format (tr ("X: %1, Y: %2, Z: %3"), m_position3D[X], m_position3D[Y], m_position3D[Z]); |
661 QFontMetrics metrics = QFontMetrics (font()); |
662 QFontMetrics metrics = QFontMetrics (font()); |
662 QRect textSize = metrics.boundingRect (0, 0, m_width, m_height, Qt::AlignCenter, text); |
663 QRect textSize = metrics.boundingRect (0, 0, m_width, m_height, Qt::AlignCenter, text); |
663 paint.setPen (textPen()); |
664 painter.setPen (textPen()); |
664 paint.drawText (m_width - textSize.width(), m_height - 16, textSize.width(), |
665 painter.drawText (m_width - textSize.width(), m_height - 16, textSize.width(), |
665 textSize.height(), Qt::AlignCenter, text); |
666 textSize.height(), Qt::AlignCenter, text); |
666 } |
667 } |
667 |
668 |
668 if (not isPicking()) |
669 if (not isPicking()) |
669 { |
670 { |
670 // Draw edit mode HUD |
671 // Draw edit mode HUD |
671 m_currentEditMode->render (paint); |
672 m_currentEditMode->render (painter); |
672 |
673 |
673 // Draw a background for the selected camera |
674 // Draw a background for the selected camera |
674 paint.setPen (m_thinBorderPen); |
675 painter.setPen (m_thinBorderPen); |
675 paint.setBrush (QBrush (QColor (0, 128, 160, 128))); |
676 painter.setBrush (QBrush (QColor (0, 128, 160, 128))); |
676 paint.drawRect (m_cameraIcons[camera()].selRect); |
677 painter.drawRect (m_cameraIcons[camera()].selRect); |
677 |
678 |
678 // Draw the camera icons |
679 // Draw the camera icons |
679 for (CameraIcon& info : m_cameraIcons) |
680 for (CameraIcon& info : m_cameraIcons) |
680 { |
681 { |
681 // Don't draw the free camera icon when we can't use the free camera |
682 // Don't draw the free camera icon when we can't use the free camera |
682 if (&info == &m_cameraIcons[EFreeCamera] and not m_currentEditMode->allowFreeCamera()) |
683 if (&info == &m_cameraIcons[EFreeCamera] and not m_currentEditMode->allowFreeCamera()) |
683 continue; |
684 continue; |
684 |
685 |
685 paint.drawPixmap (info.targetRect, *info.image, info.sourceRect); |
686 painter.drawPixmap (info.targetRect, *info.image, info.sourceRect); |
686 } |
687 } |
687 |
688 |
688 // Draw a label for the current camera in the bottom left corner |
689 // Draw a label for the current camera in the bottom left corner |
689 { |
690 { |
690 const int margin = 4; |
691 const int margin = 4; |
691 paint.setPen (textPen()); |
692 painter.setPen (textPen()); |
692 paint.drawText (QPoint (margin, height() - (margin + metrics.descent())), currentCameraName()); |
693 painter.drawText (QPoint (margin, height() - (margin + metrics.descent())), currentCameraName()); |
693 } |
694 } |
694 |
695 |
695 // Tool tips |
696 // Tool tips |
696 if (m_drawToolTip) |
697 if (m_drawToolTip) |
697 { |
698 { |
958 const int areawidth = (x1 - x0); |
958 const int areawidth = (x1 - x0); |
959 const int areaheight = (y1 - y0); |
959 const int areaheight = (y1 - y0); |
960 const qint32 numpixels = areawidth * areaheight; |
960 const qint32 numpixels = areawidth * areaheight; |
961 |
961 |
962 // Allocate space for the pixel data. |
962 // Allocate space for the pixel data. |
963 uchar* const pixeldata = new uchar[4 * numpixels]; |
963 QVector<unsigned char> pixeldata (4 * numpixels); |
964 uchar* pixelptr = &pixeldata[0]; |
964 unsigned char* pixelcursor = pixeldata.data(); |
965 |
965 |
966 // Read pixels from the color buffer. |
966 // Read pixels from the color buffer. |
967 glReadPixels (x0, m_height - y1, areawidth, areaheight, GL_RGBA, GL_UNSIGNED_BYTE, pixeldata); |
967 glReadPixels (x0, m_height - y1, areawidth, areaheight, GL_RGBA, GL_UNSIGNED_BYTE, pixeldata.data()); |
968 |
968 |
969 LDObject* removedObj = nullptr; |
969 LDObject* removedObj = nullptr; |
970 QList<qint32> indices; |
970 QSet<qint32> indices; |
971 |
971 |
972 // Go through each pixel read and add them to the selection. |
972 // Go through each pixel read and add them to the selection. |
973 // Note: black is background, those indices are skipped. |
973 // Note: black is background, those indices are skipped. |
974 for (qint32 i = 0; i < numpixels; ++i) |
974 for (qint32 i = 0; i < numpixels; ++i) |
975 { |
975 { |
976 qint32 idx = |
976 qint32 idx = (pixelcursor[0] * 0x10000) + (pixelcursor[1] * 0x100) + pixelcursor[2]; |
977 (*(pixelptr + 0) * 0x10000) + |
977 pixelcursor += 4; |
978 (*(pixelptr + 1) * 0x100) + |
|
979 *(pixelptr + 2); |
|
980 pixelptr += 4; |
|
981 |
978 |
982 if (idx != 0) |
979 if (idx != 0) |
983 indices << idx; |
980 indices << idx; |
984 } |
981 } |
985 |
|
986 removeDuplicates (indices); |
|
987 |
982 |
988 for (qint32 idx : indices) |
983 for (qint32 idx : indices) |
989 { |
984 { |
990 LDObject* obj = LDObject::fromID (idx); |
985 LDObject* obj = LDObject::fromID (idx); |
991 |
986 |