95 { QColor (80, 192, 0), vertex (0, 10000, 0) }, |
95 { QColor (80, 192, 0), vertex (0, 10000, 0) }, |
96 { QColor (0, 160, 192), vertex (0, 0, 10000) }, |
96 { QColor (0, 160, 192), vertex (0, 0, 10000) }, |
97 }; |
97 }; |
98 |
98 |
99 static bool g_glInvert = false; |
99 static bool g_glInvert = false; |
100 static QList<short> g_warnedColors; |
100 static QList<int> g_warnedColors; |
101 |
101 |
102 // ============================================================================= |
102 // ============================================================================= |
103 // ----------------------------------------------------------------------------- |
103 // ----------------------------------------------------------------------------- |
104 GLRenderer::GLRenderer (QWidget* parent) : QGLWidget (parent) |
104 GLRenderer::GLRenderer (QWidget* parent) : QGLWidget (parent) |
105 { m_picking = m_rangepick = false; |
105 { m_picking = m_rangepick = false; |
318 // not appear pitch-black. |
318 // not appear pitch-black. |
319 if (obj->color() != edgecolor) |
319 if (obj->color() != edgecolor) |
320 qcol = getMainColor(); |
320 qcol = getMainColor(); |
321 |
321 |
322 // Warn about the unknown colors, but only once. |
322 // Warn about the unknown colors, but only once. |
323 for (short i : g_warnedColors) |
323 for (int i : g_warnedColors) |
324 if (obj->color() == i) |
324 if (obj->color() == i) |
325 return; |
325 return; |
326 |
326 |
327 log ("%1: Unknown color %2!\n", __func__, obj->color()); |
327 log ("%1: Unknown color %2!\n", __func__, obj->color()); |
328 g_warnedColors << obj->color(); |
328 g_warnedColors << obj->color(); |
471 |
471 |
472 vertex pos3d; |
472 vertex pos3d; |
473 const LDFixedCameraInfo* cam = &g_FixedCameras[m_camera]; |
473 const LDFixedCameraInfo* cam = &g_FixedCameras[m_camera]; |
474 const Axis axisX = cam->axisX; |
474 const Axis axisX = cam->axisX; |
475 const Axis axisY = cam->axisY; |
475 const Axis axisY = cam->axisY; |
476 const short negXFac = cam->negX ? -1 : 1, |
476 const int negXFac = cam->negX ? -1 : 1, |
477 negYFac = cam->negY ? -1 : 1; |
477 negYFac = cam->negY ? -1 : 1; |
478 |
478 |
479 // Calculate cx and cy - these are the LDraw unit coords the cursor is at. |
479 // Calculate cx and cy - these are the LDraw unit coords the cursor is at. |
480 double cx = (-m_virtWidth + ((2 * pos2d.x() * m_virtWidth) / m_width) - pan (X)); |
480 double cx = (-m_virtWidth + ((2 * pos2d.x() * m_virtWidth) / m_width) - pan (X)); |
481 double cy = (m_virtHeight - ((2 * pos2d.y() * m_virtHeight) / m_height) - pan (Y)); |
481 double cy = (m_virtHeight - ((2 * pos2d.y() * m_virtHeight) / m_height) - pan (Y)); |
490 |
490 |
491 str tmp; |
491 str tmp; |
492 // Create the vertex from the coordinates |
492 // Create the vertex from the coordinates |
493 pos3d[axisX] = tmp.sprintf ("%.3f", cx).toDouble(); |
493 pos3d[axisX] = tmp.sprintf ("%.3f", cx).toDouble(); |
494 pos3d[axisY] = tmp.sprintf ("%.3f", cy).toDouble(); |
494 pos3d[axisY] = tmp.sprintf ("%.3f", cy).toDouble(); |
495 pos3d[3 - axisX - axisY] = depthValue(); |
495 pos3d[3 - axisX - axisY] = getDepthValue(); |
496 return pos3d; |
496 return pos3d; |
497 } |
497 } |
498 |
498 |
499 // ============================================================================= |
499 // ============================================================================= |
500 // ----------------------------------------------------------------------------- |
500 // ----------------------------------------------------------------------------- |
504 QPoint GLRenderer::coordconv3_2 (const vertex& pos3d) const |
504 QPoint GLRenderer::coordconv3_2 (const vertex& pos3d) const |
505 { GLfloat m[16]; |
505 { GLfloat m[16]; |
506 const LDFixedCameraInfo* cam = &g_FixedCameras[m_camera]; |
506 const LDFixedCameraInfo* cam = &g_FixedCameras[m_camera]; |
507 const Axis axisX = cam->axisX; |
507 const Axis axisX = cam->axisX; |
508 const Axis axisY = cam->axisY; |
508 const Axis axisY = cam->axisY; |
509 const short negXFac = cam->negX ? -1 : 1, |
509 const int negXFac = cam->negX ? -1 : 1, |
510 negYFac = cam->negY ? -1 : 1; |
510 negYFac = cam->negY ? -1 : 1; |
511 |
511 |
512 glGetFloatv (GL_MODELVIEW_MATRIX, m); |
512 glGetFloatv (GL_MODELVIEW_MATRIX, m); |
513 |
513 |
514 const double x = pos3d.x(); |
514 const double x = pos3d.x(); |
637 { // If we have not specified the center point of the circle yet, preview it on the screen. |
637 { // If we have not specified the center point of the circle yet, preview it on the screen. |
638 if (m_drawedVerts.isEmpty()) |
638 if (m_drawedVerts.isEmpty()) |
639 drawBlip (paint, coordconv3_2 (m_hoverpos)); |
639 drawBlip (paint, coordconv3_2 (m_hoverpos)); |
640 else |
640 else |
641 { QVector<vertex> verts, verts2; |
641 { QVector<vertex> verts, verts2; |
642 const double dist0 = circleDrawDist (0), |
642 const double dist0 = getCircleDrawDist (0), |
643 dist1 = (m_drawedVerts.size() >= 2) ? circleDrawDist (1) : -1; |
643 dist1 = (m_drawedVerts.size() >= 2) ? getCircleDrawDist (1) : -1; |
644 const int segs = lores; |
644 const int segs = lores; |
645 const double angleUnit = (2 * pi) / segs; |
645 const double angleUnit = (2 * pi) / segs; |
646 Axis relX, relY; |
646 Axis relX, relY; |
647 QVector<QPoint> ringpoints, circlepoints, circle2points; |
647 QVector<QPoint> ringpoints, circlepoints, circle2points; |
648 |
648 |
893 LDSubfile::DeepInline | |
893 LDSubfile::DeepInline | |
894 LDSubfile::CacheInline | |
894 LDSubfile::CacheInline | |
895 LDSubfile::RendererInline); |
895 LDSubfile::RendererInline); |
896 bool oldinvert = g_glInvert; |
896 bool oldinvert = g_glInvert; |
897 |
897 |
898 if (ref->transform().determinant() < 0) |
898 if (ref->transform().getDeterminant() < 0) |
899 g_glInvert = !g_glInvert; |
899 g_glInvert = !g_glInvert; |
900 |
900 |
901 LDObject* prev = ref->prev(); |
901 LDObject* prev = ref->prev(); |
902 |
902 |
903 if (prev && prev->getType() == LDObject::BFC && static_cast<LDBFC*> (prev)->type == LDBFC::InvertNext) |
903 if (prev && prev->getType() == LDObject::BFC && static_cast<LDBFC*> (prev)->type == LDBFC::InvertNext) |
1198 |
1198 |
1199 drawGLScene(); |
1199 drawGLScene(); |
1200 |
1200 |
1201 glGetIntegerv (GL_VIEWPORT, viewport); |
1201 glGetIntegerv (GL_VIEWPORT, viewport); |
1202 |
1202 |
1203 short x0 = mouseX, |
1203 int x0 = mouseX, |
1204 y0 = mouseY; |
1204 y0 = mouseY; |
1205 short x1, y1; |
1205 int x1, y1; |
1206 |
1206 |
1207 // Determine how big an area to read - with range picking, we pick by |
1207 // Determine how big an area to read - with range picking, we pick by |
1208 // the area given, with single pixel picking, we use an 1 x 1 area. |
1208 // the area given, with single pixel picking, we use an 1 x 1 area. |
1209 if (m_rangepick) |
1209 if (m_rangepick) |
1210 { x1 = m_rangeStart.x(); |
1210 { x1 = m_rangeStart.x(); |
1221 |
1221 |
1222 if (y0 > y1) |
1222 if (y0 > y1) |
1223 dataswap (y0, y1); |
1223 dataswap (y0, y1); |
1224 |
1224 |
1225 // Clamp the values to ensure they're within bounds |
1225 // Clamp the values to ensure they're within bounds |
1226 x0 = max<short> (0, x0); |
1226 x0 = max (0, x0); |
1227 y0 = max<short> (0, y0); |
1227 y0 = max (0, y0); |
1228 x1 = min<short> (x1, m_width); |
1228 x1 = min (x1, m_width); |
1229 y1 = min<short> (y1, m_height); |
1229 y1 = min (y1, m_height); |
1230 |
1230 |
1231 const short areawidth = (x1 - x0); |
1231 const int areawidth = (x1 - x0); |
1232 const short areaheight = (y1 - y0); |
1232 const int areaheight = (y1 - y0); |
1233 const long numpixels = areawidth * areaheight; |
1233 const qint32 numpixels = areawidth * areaheight; |
1234 |
1234 |
1235 // Allocate space for the pixel data. |
1235 // Allocate space for the pixel data. |
1236 uchar* const pixeldata = new uchar[4 * numpixels]; |
1236 uchar* const pixeldata = new uchar[4 * numpixels]; |
1237 uchar* pixelptr = &pixeldata[0]; |
1237 uchar* pixelptr = &pixeldata[0]; |
1238 |
1238 |
1242 glReadPixels (x0, viewport[3] - y1, areawidth, areaheight, GL_RGBA, GL_UNSIGNED_BYTE, pixeldata); |
1242 glReadPixels (x0, viewport[3] - y1, areawidth, areaheight, GL_RGBA, GL_UNSIGNED_BYTE, pixeldata); |
1243 |
1243 |
1244 LDObject* removedObj = null; |
1244 LDObject* removedObj = null; |
1245 |
1245 |
1246 // Go through each pixel read and add them to the selection. |
1246 // Go through each pixel read and add them to the selection. |
1247 for (long i = 0; i < numpixels; ++i) |
1247 for (qint32 i = 0; i < numpixels; ++i) |
1248 { long idx = |
1248 { qint32 idx = |
1249 (* (pixelptr + 0) * 0x10000) + |
1249 (*(pixelptr + 0) * 0x10000) + |
1250 (* (pixelptr + 1) * 0x00100) + |
1250 (*(pixelptr + 1) * 0x00100) + |
1251 (* (pixelptr + 2) * 0x00001); |
1251 (*(pixelptr + 2) * 0x00001); |
1252 pixelptr += 4; |
1252 pixelptr += 4; |
1253 |
1253 |
1254 if (idx == 0xFFFFFF) |
1254 if (idx == 0xFFFFFF) |
1255 continue; // White is background; skip |
1255 continue; // White is background; skip |
1256 |
1256 |
1348 // ----------------------------------------------------------------------------- |
1348 // ----------------------------------------------------------------------------- |
1349 SET_ACCESSOR (LDFile*, GLRenderer::setFile) |
1349 SET_ACCESSOR (LDFile*, GLRenderer::setFile) |
1350 { m_file = val; |
1350 { m_file = val; |
1351 |
1351 |
1352 if (val != null) |
1352 if (val != null) |
1353 overlaysFromObjects(); |
1353 initOverlaysFromObjects(); |
1354 } |
1354 } |
1355 |
1355 |
1356 // ============================================================================= |
1356 // ============================================================================= |
1357 // ----------------------------------------------------------------------------- |
1357 // ----------------------------------------------------------------------------- |
1358 matrix GLRenderer::getCircleDrawMatrix (double scale) |
1358 matrix GLRenderer::getCircleDrawMatrix (double scale) |
1425 } |
1425 } |
1426 } break; |
1426 } break; |
1427 |
1427 |
1428 case CircleMode: |
1428 case CircleMode: |
1429 { const int segs = lores, divs = lores; // TODO: make customizable |
1429 { const int segs = lores, divs = lores; // TODO: make customizable |
1430 double dist0 = circleDrawDist (0), |
1430 double dist0 = getCircleDrawDist (0), |
1431 dist1 = circleDrawDist (1); |
1431 dist1 = getCircleDrawDist (1); |
1432 LDFile* refFile = null; |
1432 LDFile* refFile = null; |
1433 matrix transform; |
1433 matrix transform; |
1434 bool circleOrDisc = false; |
1434 bool circleOrDisc = false; |
1435 |
1435 |
1436 if (dist1 < dist0) |
1436 if (dist1 < dist0) |
1448 transform = getCircleDrawMatrix ((dist0 != 0) ? dist0 : dist1); |
1448 transform = getCircleDrawMatrix ((dist0 != 0) ? dist0 : dist1); |
1449 circleOrDisc = true; |
1449 circleOrDisc = true; |
1450 } |
1450 } |
1451 elif (g_RingFinder (dist0, dist1)) |
1451 elif (g_RingFinder (dist0, dist1)) |
1452 { // The ring finder found a solution, use that. Add the component rings to the file. |
1452 { // The ring finder found a solution, use that. Add the component rings to the file. |
1453 for (const RingFinder::Component& cmp : g_RingFinder.bestSolution()->components()) |
1453 for (const RingFinder::Component& cmp : g_RingFinder.bestSolution()->getComponents()) |
1454 { if ((refFile = getFile (radialFileName (::Ring, lores, lores, cmp.num))) == null) |
1454 { if ((refFile = getFile (radialFileName (::Ring, lores, lores, cmp.num))) == null) |
1455 { refFile = generatePrimitive (::Ring, lores, lores, cmp.num); |
1455 { refFile = generatePrimitive (::Ring, lores, lores, cmp.num); |
1456 refFile->setImplicit (false); |
1456 refFile->setImplicit (false); |
1457 } |
1457 } |
1458 |
1458 |
1474 y0 = m_drawedVerts[0][relY]; |
1474 y0 = m_drawedVerts[0][relY]; |
1475 |
1475 |
1476 vertex templ; |
1476 vertex templ; |
1477 templ[relX] = x0; |
1477 templ[relX] = x0; |
1478 templ[relY] = y0; |
1478 templ[relY] = y0; |
1479 templ[relZ] = depthValue(); |
1479 templ[relZ] = getDepthValue(); |
1480 |
1480 |
1481 // Calculate circle coords |
1481 // Calculate circle coords |
1482 makeCircle (segs, divs, dist0, c0); |
1482 makeCircle (segs, divs, dist0, c0); |
1483 makeCircle (segs, divs, dist1, c1); |
1483 makeCircle (segs, divs, dist1, c1); |
1484 |
1484 |
1537 m_rectdraw = false; |
1537 m_rectdraw = false; |
1538 } |
1538 } |
1539 |
1539 |
1540 // ============================================================================= |
1540 // ============================================================================= |
1541 // ----------------------------------------------------------------------------- |
1541 // ----------------------------------------------------------------------------- |
1542 double GLRenderer::circleDrawDist (int pos) const |
1542 double GLRenderer::getCircleDrawDist (int pos) const |
1543 { assert (m_drawedVerts.size() >= pos + 1); |
1543 { assert (m_drawedVerts.size() >= pos + 1); |
1544 const vertex& v1 = (m_drawedVerts.size() >= pos + 2) ? m_drawedVerts[pos + 1] : m_hoverpos; |
1544 const vertex& v1 = (m_drawedVerts.size() >= pos + 2) ? m_drawedVerts[pos + 1] : m_hoverpos; |
1545 Axis relX, relY; |
1545 Axis relX, relY; |
1546 getRelativeAxes (relX, relY); |
1546 getRelativeAxes (relX, relY); |
1547 |
1547 |
1605 obj->m_glinit = true; |
1605 obj->m_glinit = true; |
1606 } |
1606 } |
1607 |
1607 |
1608 // ============================================================================= |
1608 // ============================================================================= |
1609 // ----------------------------------------------------------------------------- |
1609 // ----------------------------------------------------------------------------- |
1610 uchar* GLRenderer::screencap (int& w, int& h) |
1610 uchar* GLRenderer::getScreencap (int& w, int& h) |
1611 { w = m_width; |
1611 { w = m_width; |
1612 h = m_height; |
1612 h = m_height; |
1613 uchar* cap = new uchar[4 * w * h]; |
1613 uchar* cap = new uchar[4 * w * h]; |
1614 |
1614 |
1615 m_screencap = true; |
1615 m_screencap = true; |
1651 obj->m_glinit = false; |
1651 obj->m_glinit = false; |
1652 } |
1652 } |
1653 |
1653 |
1654 // ============================================================================= |
1654 // ============================================================================= |
1655 // ----------------------------------------------------------------------------- |
1655 // ----------------------------------------------------------------------------- |
1656 Axis GLRenderer::cameraAxis (bool y, GL::Camera camid) |
1656 Axis GLRenderer::getCameraAxis (bool y, GL::Camera camid) |
1657 { if (camid == (GL::Camera) - 1) |
1657 { if (camid == (GL::Camera) - 1) |
1658 camid = m_camera; |
1658 camid = m_camera; |
1659 |
1659 |
1660 const LDFixedCameraInfo* cam = &g_FixedCameras[camid]; |
1660 const LDFixedCameraInfo* cam = &g_FixedCameras[camid]; |
1661 return (y) ? cam->axisY : cam->axisX; |
1661 return (y) ? cam->axisY : cam->axisX; |
1685 if (info.lw == 0) |
1685 if (info.lw == 0) |
1686 info.lw = (info.lh * img->width()) / img->height(); |
1686 info.lw = (info.lh * img->width()) / img->height(); |
1687 elif (info.lh == 0) |
1687 elif (info.lh == 0) |
1688 info.lh = (info.lw * img->height()) / img->width(); |
1688 info.lh = (info.lw * img->height()) / img->width(); |
1689 |
1689 |
1690 const Axis x2d = cameraAxis (false, cam), |
1690 const Axis x2d = getCameraAxis (false, cam), |
1691 y2d = cameraAxis (true, cam); |
1691 y2d = getCameraAxis (true, cam); |
1692 const double negXFac = g_FixedCameras[cam].negX ? -1 : 1, |
1692 const double negXFac = g_FixedCameras[cam].negX ? -1 : 1, |
1693 negYFac = g_FixedCameras[cam].negY ? -1 : 1; |
1693 negYFac = g_FixedCameras[cam].negY ? -1 : 1; |
1694 |
1694 |
1695 info.v0 = info.v1 = g_origin; |
1695 info.v0 = info.v1 = g_origin; |
1696 info.v0[x2d] = - (info.ox * info.lw * negXFac) / img->width(); |
1696 info.v0[x2d] = - (info.ox * info.lw * negXFac) / img->width(); |
1729 m_depthValues[camera()] = depth; |
1729 m_depthValues[camera()] = depth; |
1730 } |
1730 } |
1731 |
1731 |
1732 // ============================================================================= |
1732 // ============================================================================= |
1733 // ----------------------------------------------------------------------------- |
1733 // ----------------------------------------------------------------------------- |
1734 double GLRenderer::depthValue() const |
1734 double GLRenderer::getDepthValue() const |
1735 { assert (camera() < Free); |
1735 { assert (camera() < Free); |
1736 return m_depthValues[camera()]; |
1736 return m_depthValues[camera()]; |
1737 } |
1737 } |
1738 |
1738 |
1739 // ============================================================================= |
1739 // ============================================================================= |
1740 // ----------------------------------------------------------------------------- |
1740 // ----------------------------------------------------------------------------- |
1741 const char* GLRenderer::cameraName() const |
1741 const char* GLRenderer::getCameraName() const |
1742 { return g_CameraNames[camera()]; |
1742 { return g_CameraNames[camera()]; |
1743 } |
1743 } |
1744 |
1744 |
1745 // ============================================================================= |
1745 // ============================================================================= |
1746 // ----------------------------------------------------------------------------- |
1746 // ----------------------------------------------------------------------------- |
1863 } |
1863 } |
1864 |
1864 |
1865 vertex v0 = m_drawedVerts[0], |
1865 vertex v0 = m_drawedVerts[0], |
1866 v1 = (m_drawedVerts.size() >= 2) ? m_drawedVerts[1] : m_hoverpos; |
1866 v1 = (m_drawedVerts.size() >= 2) ? m_drawedVerts[1] : m_hoverpos; |
1867 |
1867 |
1868 const Axis ax = cameraAxis (false), |
1868 const Axis ax = getCameraAxis (false), |
1869 ay = cameraAxis (true), |
1869 ay = getCameraAxis (true), |
1870 az = (Axis) (3 - ax - ay); |
1870 az = (Axis) (3 - ax - ay); |
1871 |
1871 |
1872 for (int i = 0; i < 4; ++i) |
1872 for (int i = 0; i < 4; ++i) |
1873 m_rectverts[i][az] = depthValue(); |
1873 m_rectverts[i][az] = getDepthValue(); |
1874 |
1874 |
1875 m_rectverts[0][ax] = v0[ax]; |
1875 m_rectverts[0][ax] = v0[ax]; |
1876 m_rectverts[0][ay] = v0[ay]; |
1876 m_rectverts[0][ay] = v0[ay]; |
1877 m_rectverts[1][ax] = v1[ax]; |
1877 m_rectverts[1][ax] = v1[ax]; |
1878 m_rectverts[1][ay] = v0[ay]; |
1878 m_rectverts[1][ay] = v0[ay]; |
1917 |
1917 |
1918 // ============================================================================= |
1918 // ============================================================================= |
1919 // ----------------------------------------------------------------------------- |
1919 // ----------------------------------------------------------------------------- |
1920 // Read in overlays from the current file and update overlay info accordingly. |
1920 // Read in overlays from the current file and update overlay info accordingly. |
1921 // ----------------------------------------------------------------------------- |
1921 // ----------------------------------------------------------------------------- |
1922 void GLRenderer::overlaysFromObjects() |
1922 void GLRenderer::initOverlaysFromObjects() |
1923 { for (Camera cam : g_Cameras) |
1923 { for (Camera cam : g_Cameras) |
1924 { if (cam == Free) |
1924 { if (cam == Free) |
1925 continue; |
1925 continue; |
1926 |
1926 |
1927 LDGLOverlay& meta = m_overlays[cam]; |
1927 LDGLOverlay& meta = m_overlays[cam]; |
1970 // object and put an empty object after it (though don't do this if |
1970 // object and put an empty object after it (though don't do this if |
1971 // there was no schemantic elements at all) |
1971 // there was no schemantic elements at all) |
1972 int i, lastOverlay = -1; |
1972 int i, lastOverlay = -1; |
1973 bool found = false; |
1973 bool found = false; |
1974 |
1974 |
1975 for (i = 0; i < file()->numObjs(); ++i) |
1975 for (i = 0; i < file()->getObjectCount(); ++i) |
1976 { LDObject* obj = file()->obj (i); |
1976 { LDObject* obj = file()->getObject (i); |
1977 |
1977 |
1978 if (obj->isScemantic()) |
1978 if (obj->isScemantic()) |
1979 { found = true; |
1979 { found = true; |
1980 break; |
1980 break; |
1981 } |
1981 } |