--- a/src/gldraw.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/gldraw.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -36,14 +36,11 @@ #include "addObjectDialog.h" #include "messagelog.h" #include "gldata.h" -#include "build/moc_gldraw.cpp" +#include "primitives.h" +#include "moc_gldraw.cpp" -static const struct staticCameraMeta { - const int8 glrotate[3]; - const Axis axisX, axisY; - const bool negX, negY; -} g_staticCameras[6] = { - {{ 1, 0, 0 }, X, Z, false, false }, +static const LDFixedCameraInfo g_FixedCameras[6] = +{ {{ 1, 0, 0 }, X, Z, false, false }, {{ 0, 0, 0 }, X, Y, false, true }, {{ 0, 1, 0 }, Z, Y, true, true }, {{ -1, 0, 0 }, X, Z, false, true }, @@ -51,6 +48,12 @@ {{ 0, -1, 0 }, Z, Y, false, true }, }; +static const matrix g_circleDrawTransforms[3] = +{ { 2, 0, 0, 0, 1, 0, 0, 0, 2 }, + { 2, 0, 0, 0, 0, 2, 0, 1, 0 }, + { 0, 1, 0, 2, 0, 0, 0, 0, 2 }, +}; + cfg (String, gl_bgcolor, "#CCCCD9"); cfg (String, gl_maincolor, "#707078"); cfg (Float, gl_maincolor_alpha, 1.0); @@ -60,20 +63,21 @@ cfg (Bool, gl_axes, false); cfg (Bool, gl_wireframe, false); cfg (Bool, gl_logostuds, false); +cfg (Bool, gl_aa, true); // argh -const char* g_CameraNames[7] = { - QT_TRANSLATE_NOOP ("GLRenderer", "Top"), - QT_TRANSLATE_NOOP ("GLRenderer", "Front"), - QT_TRANSLATE_NOOP ("GLRenderer", "Left"), - QT_TRANSLATE_NOOP ("GLRenderer", "Bottom"), - QT_TRANSLATE_NOOP ("GLRenderer", "Back"), - QT_TRANSLATE_NOOP ("GLRenderer", "Right"), - QT_TRANSLATE_NOOP ("GLRenderer", "Free") +const char* g_CameraNames[7] = +{ QT_TRANSLATE_NOOP ("GLRenderer", "Top"), + QT_TRANSLATE_NOOP ("GLRenderer", "Front"), + QT_TRANSLATE_NOOP ("GLRenderer", "Left"), + QT_TRANSLATE_NOOP ("GLRenderer", "Bottom"), + QT_TRANSLATE_NOOP ("GLRenderer", "Back"), + QT_TRANSLATE_NOOP ("GLRenderer", "Right"), + QT_TRANSLATE_NOOP ("GLRenderer", "Free") }; -const GL::Camera g_Cameras[7] = { - GL::Top, +const GL::Camera g_Cameras[7] = +{ GL::Top, GL::Front, GL::Left, GL::Bottom, @@ -82,19 +86,19 @@ GL::Free }; -const struct GLAxis { - const QColor col; +const struct LDGLAxis +{ const QColor col; const vertex vert; -} g_GLAxes[3] = { - { QColor (255, 0, 0), vertex (10000, 0, 0) }, +} g_GLAxes[3] = +{ { QColor (255, 0, 0), vertex (10000, 0, 0) }, { QColor (80, 192, 0), vertex (0, 10000, 0) }, { QColor (0, 160, 192), vertex (0, 0, 10000) }, }; // ============================================================================= // ----------------------------------------------------------------------------- -GLRenderer::GLRenderer (QWidget* parent) : QGLWidget (parent) { - m_picking = m_rangepick = false; +GLRenderer::GLRenderer (QWidget* parent) : QGLWidget (parent) +{ m_picking = m_rangepick = false; m_camera = (GL::Camera) gl_camera.value; m_drawToolTip = false; m_editMode = Select; @@ -102,94 +106,123 @@ m_panning = false; setFile (null); setDrawOnly (false); - resetAngles(); setMessageLog (null); - + m_width = m_height = -1; + m_hoverpos = g_origin; + m_toolTipTimer = new QTimer (this); m_toolTipTimer->setSingleShot (true); connect (m_toolTipTimer, SIGNAL (timeout()), this, SLOT (slot_toolTipTimer())); - + m_thickBorderPen = QPen (QColor (0, 0, 0, 208), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); m_thinBorderPen = m_thickBorderPen; m_thinBorderPen.setWidth (1); - + // Init camera icons - for (const GL::Camera cam : g_Cameras) { - str iconname = fmt ("camera-%1", tr (g_CameraNames[cam]).toLower()); - + for (const GL::Camera cam : g_Cameras) + { str iconname = fmt ("camera-%1", tr (g_CameraNames[cam]).toLower()); + CameraIcon* info = &m_cameraIcons[cam]; info->img = new QPixmap (getIcon (iconname)); info->cam = cam; } - - for (int i = 0; i < 6; ++i) { - m_overlays[i].img = null; + + for (int i = 0; i < 6; ++i) + { m_overlays[i].img = null; m_depthValues[i] = 0.0f; } - + calcCameraIcons(); } // ============================================================================= // ----------------------------------------------------------------------------- -GLRenderer::~GLRenderer() { - for (int i = 0; i < 6; ++i) +GLRenderer::~GLRenderer() +{ for (int i = 0; i < 6; ++i) delete m_overlays[i].img; - + for (CameraIcon& info : m_cameraIcons) delete info.img; } // ============================================================================= +// Calculates the "hitboxes" of the camera icons so that we can tell when the +// cursor is pointing at the camera icon. // ----------------------------------------------------------------------------- -void GLRenderer::calcCameraIcons() { - ushort i = 0; - - for (CameraIcon& info : m_cameraIcons) { +void GLRenderer::calcCameraIcons() +{ int i = 0; + + for (CameraIcon& info : m_cameraIcons) + { // MATH const long x1 = (m_width - (info.cam != Free ? 48 : 16)) + ((i % 3) * 16) - 1, y1 = ((i / 3) * 16) + 1; - + info.srcRect = QRect (0, 0, 16, 16); info.destRect = QRect (x1, y1, 16, 16); - info.selRect = QRect (info.destRect.x(), info.destRect.y(), - info.destRect.width() + 1, info.destRect.height() + 1); + info.selRect = QRect ( + info.destRect.x(), + info.destRect.y(), + info.destRect.width() + 1, + info.destRect.height() + 1 + ); + ++i; } } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::initGLData() { - glEnable (GL_BLEND); +void GLRenderer::initGLData() +{ glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable (GL_POLYGON_OFFSET_FILL); glPolygonOffset (1.0f, 1.0f); - + glEnable (GL_DEPTH_TEST); glShadeModel (GL_SMOOTH); glEnable (GL_MULTISAMPLE); - - glEnable (GL_LINE_SMOOTH); - glHint (GL_LINE_SMOOTH_HINT, GL_NICEST); + + if (gl_aa) + { glEnable (GL_LINE_SMOOTH); + glEnable (GL_POLYGON_SMOOTH); + glHint (GL_LINE_SMOOTH_HINT, GL_NICEST); + glHint (GL_POLYGON_SMOOTH_HINT, GL_NICEST); + } else + { glDisable (GL_LINE_SMOOTH); + glDisable (GL_POLYGON_SMOOTH); + } } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::resetAngles() { - m_rotX = 30.0f; - m_rotY = 325.f; - m_panX = m_panY = m_rotZ = 0.0f; +void GLRenderer::resetAngles() +{ rot (X) = 30.0f; + rot (Y) = 325.f; + pan (X) = pan (Y) = rot (Z) = 0.0f; zoomToFit(); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::initializeGL() { - setBackground(); - +void GLRenderer::resetAllAngles() +{ Camera oldcam = camera(); + + for (int i = 0; i < 7; ++i) + { setCamera ((Camera) i); + resetAngles(); + } + + setCamera (oldcam); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void GLRenderer::initializeGL() +{ setBackground(); + glLineWidth (gl_linethickness); glLineStipple (1, 0x6666); - + setAutoFillBackground (false); setMouseTracking (true); setFocusPolicy (Qt::WheelFocus); @@ -199,26 +232,26 @@ // ============================================================================= // ----------------------------------------------------------------------------- -QColor GLRenderer::getMainColor() { - QColor col (gl_maincolor); - +QColor GLRenderer::getMainColor() +{ QColor col (gl_maincolor); + if (!col.isValid()) return QColor (0, 0, 0); - + col.setAlpha (gl_maincolor_alpha * 255.f); return col; } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::setBackground() { - QColor col (gl_bgcolor); - +void GLRenderer::setBackground() +{ QColor col (gl_bgcolor); + if (!col.isValid()) return; - + col.setAlpha (255); - + m_darkbg = luma (col) < 80; m_bgcolor = col; qglClearColor (col); @@ -236,18 +269,18 @@ void GLRenderer::hardRefresh() { g_vertexCompiler.compileFile(); refresh(); - + glLineWidth (gl_linethickness); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::resizeGL (int w, int h) { - m_width = w; +void GLRenderer::resizeGL (int w, int h) +{ m_width = w; m_height = h; - + calcCameraIcons(); - + glViewport (0, 0, w, h); glMatrixMode (GL_PROJECTION); glLoadIdentity(); @@ -257,61 +290,62 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::drawGLScene() { - if (file() == null) +void GLRenderer::drawGLScene() +{ if (file() == null) return; - + if (gl_wireframe && !picking()) glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); - + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable (GL_DEPTH_TEST); - - if (m_camera != Free) { - glMatrixMode (GL_PROJECTION); + + if (m_camera != Free) + { glMatrixMode (GL_PROJECTION); glPushMatrix(); - + glLoadIdentity(); glOrtho (-m_virtWidth, m_virtWidth, -m_virtHeight, m_virtHeight, -100.0f, 100.0f); - glTranslatef (m_panX, m_panY, 0.0f); - - if (m_camera != Front && m_camera != Back) { - glRotatef (90.0f, g_staticCameras[m_camera].glrotate[0], - g_staticCameras[m_camera].glrotate[1], - g_staticCameras[m_camera].glrotate[2]); + glTranslatef (pan (X), pan (Y), 0.0f); + + if (m_camera != Front && m_camera != Back) + { glRotatef (90.0f, g_FixedCameras[camera()].glrotate[0], + g_FixedCameras[camera()].glrotate[1], + g_FixedCameras[camera()].glrotate[2]); } - + // Back camera needs to be handled differently - if (m_camera == GL::Back) { - glRotatef (180.0f, 1.0f, 0.0f, 0.0f); + if (m_camera == GL::Back) + { glRotatef (180.0f, 1.0f, 0.0f, 0.0f); glRotatef (180.0f, 0.0f, 0.0f, 1.0f); } - } else { - glMatrixMode (GL_MODELVIEW); + } + else + { glMatrixMode (GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); - + glTranslatef (0.0f, 0.0f, -2.0f); - glTranslatef (m_panX, m_panY, -zoom()); - glRotatef (m_rotX, 1.0f, 0.0f, 0.0f); - glRotatef (m_rotY, 0.0f, 1.0f, 0.0f); - glRotatef (m_rotZ, 0.0f, 0.0f, 1.0f); + glTranslatef (pan (X), pan (Y), -zoom()); + glRotatef (rot (X), 1.0f, 0.0f, 0.0f); + glRotatef (rot (Y), 0.0f, 1.0f, 0.0f); + glRotatef (rot (Z), 0.0f, 0.0f, 1.0f); } // Draw the VAOs now glEnableClientState (GL_VERTEX_ARRAY); glEnableClientState (GL_COLOR_ARRAY); glDisableClientState (GL_NORMAL_ARRAY); - + if (gl_colorbfc) { glEnable (GL_CULL_FACE); glCullFace (GL_CCW); } else glDisable (GL_CULL_FACE); - + drawVAOs ((m_picking ? PickArray : gl_colorbfc ? BFCArray : MainArray), GL_TRIANGLES); drawVAOs ((m_picking ? EdgePickArray : EdgeArray), GL_LINES); - + // Draw conditional lines. Note that conditional lines are drawn into // EdgePickArray in the picking scene, so when picking, don't do anything // here. @@ -320,7 +354,7 @@ drawVAOs (CondEdgeArray, GL_LINES); glDisable (GL_LINE_STIPPLE); } - + glPopMatrix(); glMatrixMode (GL_MODELVIEW); glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); @@ -339,28 +373,28 @@ // This converts a 2D point on the screen to a 3D point in the model. If 'snap' // is true, the 3D point will snap to the current grid. // ----------------------------------------------------------------------------- -vertex GLRenderer::coordconv2_3 (const QPoint& pos2d, bool snap) const { - assert (camera() != Free); - +vertex GLRenderer::coordconv2_3 (const QPoint& pos2d, bool snap) const +{ assert (camera() != Free); + vertex pos3d; - const staticCameraMeta* cam = &g_staticCameras[m_camera]; + const LDFixedCameraInfo* cam = &g_FixedCameras[m_camera]; const Axis axisX = cam->axisX; const Axis axisY = cam->axisY; const short negXFac = cam->negX ? -1 : 1, - negYFac = cam->negY ? -1 : 1; - + negYFac = cam->negY ? -1 : 1; + // Calculate cx and cy - these are the LDraw unit coords the cursor is at. - double cx = (-m_virtWidth + ((2 * pos2d.x() * m_virtWidth) / m_width) - m_panX); - double cy = (m_virtHeight - ((2 * pos2d.y() * m_virtHeight) / m_height) - m_panY); - - if (snap) { - cx = Grid::snap (cx, (Grid::Config) axisX); + double cx = (-m_virtWidth + ((2 * pos2d.x() * m_virtWidth) / m_width) - pan (X)); + double cy = (m_virtHeight - ((2 * pos2d.y() * m_virtHeight) / m_height) - pan (Y)); + + if (snap) + { cx = Grid::snap (cx, (Grid::Config) axisX); cy = Grid::snap (cy, (Grid::Config) axisY); } - + cx *= negXFac; cy *= negYFac; - + str tmp; // Create the vertex from the coordinates pos3d[axisX] = tmp.sprintf ("%.3f", cx).toDouble(); @@ -374,203 +408,286 @@ // Inverse operation for the above - convert a 3D position to a 2D screen // position // ----------------------------------------------------------------------------- -QPoint GLRenderer::coordconv3_2 (const vertex& pos3d) const { - GLfloat m[16]; - const staticCameraMeta* cam = &g_staticCameras[m_camera]; +QPoint GLRenderer::coordconv3_2 (const vertex& pos3d) const +{ GLfloat m[16]; + const LDFixedCameraInfo* cam = &g_FixedCameras[m_camera]; const Axis axisX = cam->axisX; const Axis axisY = cam->axisY; const short negXFac = cam->negX ? -1 : 1, - negYFac = cam->negY ? -1 : 1; - + negYFac = cam->negY ? -1 : 1; + glGetFloatv (GL_MODELVIEW_MATRIX, m); - + const double x = pos3d.x(); const double y = pos3d.y(); const double z = pos3d.z(); - + vertex transformed; transformed[X] = (m[0] * x) + (m[1] * y) + (m[2] * z) + m[3]; transformed[Y] = (m[4] * x) + (m[5] * y) + (m[6] * z) + m[7]; transformed[Z] = (m[8] * x) + (m[9] * y) + (m[10] * z) + m[11]; - - double rx = (((transformed[axisX] * negXFac) + m_virtWidth + m_panX) * m_width) / (2 * m_virtWidth); - double ry = (((transformed[axisY] * negYFac) - m_virtHeight + m_panY) * m_height) / (2 * m_virtHeight); - + + double rx = (((transformed[axisX] * negXFac) + m_virtWidth + pan (X)) * m_width) / (2 * m_virtWidth); + double ry = (((transformed[axisY] * negYFac) - m_virtHeight + pan (Y)) * m_height) / (2 * m_virtHeight); + return QPoint (rx, -ry); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::paintEvent (QPaintEvent* ev) { - Q_UNUSED (ev) - +void GLRenderer::paintEvent (QPaintEvent* ev) +{ Q_UNUSED (ev) + makeCurrent(); m_virtWidth = zoom(); m_virtHeight = (m_height * m_virtWidth) / m_width; - + initGLData(); drawGLScene(); - + + const QPen textpen = getTextPen(); + const QBrush polybrush (QColor (64, 192, 0, 128)); QPainter paint (this); QFontMetrics metrics = QFontMetrics (QFont()); paint.setRenderHint (QPainter::HighQualityAntialiasing); - + // If we wish to only draw the brick, stop here if (drawOnly()) return; - - if (m_camera != Free && !picking()) { - // Paint the overlay image if we have one - const overlayMeta& overlay = m_overlays[m_camera]; - if (overlay.img != null) { - QPoint v0 = coordconv3_2 (m_overlays[m_camera].v0), - v1 = coordconv3_2 (m_overlays[m_camera].v1); - + + if (m_camera != Free && !picking()) + { // Paint the overlay image if we have one + const LDGLOverlay& overlay = m_overlays[m_camera]; + + if (overlay.img != null) + { QPoint v0 = coordconv3_2 (m_overlays[m_camera].v0), + v1 = coordconv3_2 (m_overlays[m_camera].v1); + QRect targRect (v0.x(), v0.y(), abs (v1.x() - v0.x()), abs (v1.y() - v0.y())), - srcRect (0, 0, overlay.img->width(), overlay.img->height()); + srcRect (0, 0, overlay.img->width(), overlay.img->height()); paint.drawImage (targRect, *overlay.img, srcRect); } - + // Paint the coordinates onto the screen. str text = fmt (tr ("X: %1, Y: %2, Z: %3"), m_hoverpos[X], m_hoverpos[Y], m_hoverpos[Z]); - + QFontMetrics metrics = QFontMetrics (font()); QRect textSize = metrics.boundingRect (0, 0, m_width, m_height, Qt::AlignCenter, text); - + paint.setPen (getTextPen()); paint.drawText (m_width - textSize.width(), m_height - 16, textSize.width(), textSize.height(), Qt::AlignCenter, text); - + + QPen linepen = m_thinBorderPen; + linepen.setWidth (2); + linepen.setColor (luma (m_bgcolor) < 40 ? Qt::white : Qt::black); + // If we're drawing, draw the vertices onto the screen. - if (editMode() == Draw) { - const short blipsize = 8; - int numverts = 4; - + if (editMode() == Draw) + { int numverts = 4; + if (!m_rectdraw) numverts = m_drawedVerts.size() + 1; - - if (numverts > 0) { - QPoint poly[4]; + + if (numverts > 0) + { QPoint poly[4]; vertex polyverts[4]; - - if (!m_rectdraw) { - uchar i = 0; - for (vertex& vert : m_drawedVerts) { - poly[i] = coordconv3_2 (vert); + + if (!m_rectdraw) + { uchar i = 0; + + for (vertex& vert : m_drawedVerts) + { poly[i] = coordconv3_2 (vert); polyverts[i] = vert; ++i; } - + // Draw the cursor vertex as the last one in the list. - if (numverts <= 4) { - poly[i] = coordconv3_2 (m_hoverpos); + if (numverts <= 4) + { poly[i] = coordconv3_2 (m_hoverpos); polyverts[i] = m_hoverpos; - } else { - numverts = 4; + } + else + { numverts = 4; } - } else { - if (m_drawedVerts.size() > 0) { - // Get vertex information from m_rectverts - for (int i = 0; i < numverts; ++i) { - polyverts[i] = m_rectverts[i]; + } + else + { if (m_drawedVerts.size() > 0) + { // Get vertex information from m_rectverts + for (int i = 0; i < numverts; ++i) + { polyverts[i] = m_rectverts[i]; poly[i] = coordconv3_2 (polyverts[i]); } - } else { - poly[0] = coordconv3_2 (m_hoverpos); + } + else + { poly[0] = coordconv3_2 (m_hoverpos); polyverts[0] = m_hoverpos; } } - + // Draw the polygon-to-be - QPen pen = m_thinBorderPen; - pen.setWidth (2); - pen.setColor (luma (m_bgcolor) < 40 ? Qt::white : Qt::black); - paint.setPen (pen); - paint.setBrush (QColor (64, 192, 0, 128)); + paint.setPen (linepen); + paint.setBrush (polybrush); paint.drawPolygon (poly, numverts); - + // Draw vertex blips - pen = m_thinBorderPen; - pen.setWidth (1); - paint.setPen (pen); - paint.setBrush (QColor (64, 192, 0)); - - for (ushort i = 0; i < numverts; ++i) { - QPoint& blip = poly[i]; - paint.drawEllipse (blip.x() - blipsize / 2, blip.y() - blipsize / 2, - blipsize, blipsize); - + for (int i = 0; i < numverts; ++i) + { QPoint& blip = poly[i]; + drawBlip (paint, blip); + // Draw their coordinates paint.drawText (blip.x(), blip.y() - 8, polyverts[i].stringRep (true)); } } } + elif (editMode() == CircleMode) + { // If we have not specified the center point of the circle yet, preview it on the screen. + if (m_drawedVerts.isEmpty()) + drawBlip (paint, coordconv3_2 (m_hoverpos)); + else + { QVector<vertex> verts, verts2; + const double dist0 = circleDrawDist (0), + dist1 = (m_drawedVerts.size() >= 2) ? circleDrawDist (1) : -1; + const int segs = lores; + const double angleUnit = (2 * pi) / segs; + Axis relX, relY; + QVector<QPoint> ringpoints, circlepoints, circle2points; + + getRelativeAxes (relX, relY); + + // Calculate the preview positions of vertices + for (int i = 0; i < segs; ++i) + { vertex v = g_origin; + v[relX] = m_drawedVerts[0][relX] + (cos (i * angleUnit) * dist0); + v[relY] = m_drawedVerts[0][relY] + (sin (i * angleUnit) * dist0); + verts << v; + + if (dist1 != -1) + { v[relX] = m_drawedVerts[0][relX] + (cos (i * angleUnit) * dist1); + v[relY] = m_drawedVerts[0][relY] + (sin (i * angleUnit) * dist1); + verts2 << v; + } + } + + int i = 0; + for (const vertex& v : verts + verts2) + { // Calculate the 2D point of the vertex + QPoint point = coordconv3_2 (v); + + // Draw a green blip at where it is + drawBlip (paint, point); + + // Add it to the list of points for the green ring fill. + ringpoints << point; + + // Also add the circle points to separate lists + if (i < verts.size()) + circlepoints << point; + else + circle2points << point; + + ++i; + } + + // Insert the first point as the seventeenth one so that + // the ring polygon is closed properly. + if (ringpoints.size() >= 16) + ringpoints.insert (16, ringpoints[0]); + + // Same for the outer ring. Note that the indices are offset by 1 + // because of the insertion done above bumps the values. + if (ringpoints.size() >= 33) + ringpoints.insert (33, ringpoints[17]); + + // Draw the ring + paint.setBrush ((m_drawedVerts.size() >= 2) ? polybrush : Qt::NoBrush); + paint.setPen (Qt::NoPen); + paint.drawPolygon (QPolygon (ringpoints)); + + // Draw the circles + paint.setBrush (Qt::NoBrush); + paint.setPen (linepen); + paint.drawPolygon (QPolygon (circlepoints)); + paint.drawPolygon (QPolygon (circle2points)); + + { // Draw the current radius in the middle of the circle. + QPoint origin = coordconv3_2 (m_drawedVerts[0]); + str label = str::number (dist0); + paint.setPen (textpen); + paint.drawText (origin.x() - (metrics.width (label) / 2), origin.y(), label); + + if (m_drawedVerts.size() >= 2) + { label = str::number (dist1); + paint.drawText (origin.x() - (metrics.width (label) / 2), origin.y() + metrics.height(), label); + } + } + } + } } - + // Camera icons - if (!m_picking) { - // Draw a background for the selected camera + if (!m_picking) + { // Draw a background for the selected camera paint.setPen (m_thinBorderPen); paint.setBrush (QBrush (QColor (0, 128, 160, 128))); paint.drawRect (m_cameraIcons[camera()].selRect); - + // Draw the actual icons - for (CameraIcon& info : m_cameraIcons) { - // Don't draw the free camera icon when in draw mode + for (CameraIcon& info : m_cameraIcons) + { // Don't draw the free camera icon when in draw mode if (&info == &m_cameraIcons[GL::Free] && editMode() != Select) continue; - + paint.drawPixmap (info.destRect, *info.img, info.srcRect); } - + str fmtstr = tr ("%1 Camera"); - + // Draw a label for the current camera in the bottom left corner - { - const ushort margin = 4; - + { const int margin = 4; + str label; label = fmt (fmtstr, tr (g_CameraNames[camera()])); - paint.setPen (getTextPen()); - paint.drawText (QPoint (margin, height() - (margin + metrics.descent())), label); + paint.setPen (textpen); + paint.drawText (QPoint (margin, height() - (margin + metrics.descent())), label); } - + // Tool tips - if (m_drawToolTip) { - if (m_cameraIcons[m_toolTipCamera].destRect.contains (m_pos) == false) + if (m_drawToolTip) + { if (m_cameraIcons[m_toolTipCamera].destRect.contains (m_pos) == false) m_drawToolTip = false; - else { - str label = fmt (fmtstr, tr (g_CameraNames[m_toolTipCamera])); + else + { str label = fmt (fmtstr, tr (g_CameraNames[m_toolTipCamera])); QToolTip::showText (m_globalpos, label); } } } - + // Message log - if (msglog()) { - int y = 0; + if (msglog()) + { int y = 0; const int margin = 2; QColor penColor = getTextPen(); - - for (const MessageManager::Line& line : msglog()->getLines()) { - penColor.setAlphaF (line.alpha); + + for (const MessageManager::Line& line : msglog()->getLines()) + { penColor.setAlphaF (line.alpha); paint.setPen (penColor); paint.drawText (QPoint (margin, y + margin + metrics.ascent()), line.text); y += metrics.height(); } } - + // If we're range-picking, draw a rectangle encompassing the selection area. - if (m_rangepick && !m_picking && m_totalmove >= 10) { - const short x0 = m_rangeStart.x(), + if (m_rangepick && !m_picking && m_totalmove >= 10) + { int x0 = m_rangeStart.x(), y0 = m_rangeStart.y(), x1 = m_pos.x(), y1 = m_pos.y(); - + QRect rect (x0, y0, x1 - x0, y1 - y0); QColor fillColor = (m_addpick ? "#40FF00" : "#00CCFF"); fillColor.setAlphaF (0.2f); - + paint.setPen (m_thickBorderPen); paint.setBrush (QBrush (fillColor)); paint.drawRect (rect); @@ -579,143 +696,161 @@ // ============================================================================= // ----------------------------------------------------------------------------- -QColor GLRenderer::getTextPen () const { - return m_darkbg ? Qt::white : Qt::black; +void GLRenderer::drawBlip (QPainter& paint, QPoint pos) const +{ QPen pen = m_thinBorderPen; + const int blipsize = 8; + pen.setWidth (1); + paint.setPen (pen); + paint.setBrush (QColor (64, 192, 0)); + paint.drawEllipse (pos.x() - blipsize / 2, pos.y() - blipsize / 2, blipsize, blipsize); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::compileAllObjects() { - g_vertexCompiler.compileFile(); +void GLRenderer::compileAllObjects() +{ g_vertexCompiler.compileFile(); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::clampAngle (double& angle) const { - while (angle < 0) +void GLRenderer::clampAngle (double& angle) const +{ while (angle < 0) angle += 360.0; + while (angle > 360.0) angle -= 360.0; } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::addDrawnVertex (vertex pos) { - // If we picked an already-existing vertex, stop drawing - for (vertex& vert : m_drawedVerts) { - if (vert == pos) { - endDraw (true); - return; +void GLRenderer::addDrawnVertex (vertex pos) +{ // If we picked an already-existing vertex, stop drawing + if (editMode() != CircleMode) + { for (vertex& vert : m_drawedVerts) + { if (vert == pos) + { endDraw (true); + return; + } } } - + m_drawedVerts << pos; } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::mouseReleaseEvent (QMouseEvent* ev) { - const bool wasLeft = (m_lastButtons & Qt::LeftButton) && !(ev->buttons() & Qt::LeftButton), - wasRight = (m_lastButtons & Qt::RightButton) && !(ev->buttons() & Qt::RightButton), - wasMid = (m_lastButtons & Qt::MidButton) && !(ev->buttons() & Qt::MidButton); - +void GLRenderer::mouseReleaseEvent (QMouseEvent* ev) +{ const bool wasLeft = (m_lastButtons & Qt::LeftButton) && ! (ev->buttons() & Qt::LeftButton), + wasRight = (m_lastButtons & Qt::RightButton) && ! (ev->buttons() & Qt::RightButton), + wasMid = (m_lastButtons & Qt::MidButton) && ! (ev->buttons() & Qt::MidButton); + if (m_panning) m_panning = false; - - if (wasLeft) { - // Check if we selected a camera icon - if (!m_rangepick) { - for (CameraIcon& info : m_cameraIcons) { - if (info.destRect.contains (ev->pos())) { - setCamera (info.cam); + + if (wasLeft) + { // Check if we selected a camera icon + if (!m_rangepick) + { for (CameraIcon & info : m_cameraIcons) + { if (info.destRect.contains (ev->pos())) + { setCamera (info.cam); goto end; } } } - - switch (editMode()) { - case Draw: - if (m_rectdraw) { - if (m_drawedVerts.size() == 2) { - endDraw (true); - return; + + switch (editMode()) + { + case Draw: + { if (m_rectdraw) + { if (m_drawedVerts.size() == 2) + { endDraw (true); + return; + } } - } else { - // If we have 4 verts, stop drawing. - if (m_drawedVerts.size() >= 4) { - endDraw (true); + else + { // If we have 4 verts, stop drawing. + if (m_drawedVerts.size() >= 4) + { endDraw (true); + return; + } + + if (m_drawedVerts.isEmpty() && ev->modifiers() & Qt::ShiftModifier) + { m_rectdraw = true; + updateRectVerts(); + } + } + + addDrawnVertex (m_hoverpos); + } break; + + case CircleMode: + { if (m_drawedVerts.size() == 3) + { endDraw (true); return; } - - if (m_drawedVerts.size() == 0 && ev->modifiers() & Qt::ShiftModifier) { - m_rectdraw = true; - updateRectVerts(); + + addDrawnVertex (m_hoverpos); + } break; + + case Select: + { if (!drawOnly()) + { if (m_totalmove < 10) + m_rangepick = false; + + if (!m_rangepick) + m_addpick = (m_keymods & Qt::ControlModifier); + + if (m_totalmove < 10 || m_rangepick) + pick (ev->x(), ev->y()); } - } - - addDrawnVertex (m_hoverpos); - break; - - case Select: - if (!drawOnly()) { - if (m_totalmove < 10) - m_rangepick = false; - - if (!m_rangepick) - m_addpick = (m_keymods & Qt::ControlModifier); - - if (m_totalmove < 10 || m_rangepick) - pick (ev->x(), ev->y()); - } - - break; + } break; } - + m_rangepick = false; } - - if (wasMid && editMode() == Draw && m_drawedVerts.size() < 4 && m_totalmove < 10) { - // Find the closest vertex to our cursor + + if (wasMid && editMode() != Select && m_drawedVerts.size() < 4 && m_totalmove < 10) + { // Find the closest vertex to our cursor double mindist = 1024.0f; vertex closest; bool valid = false; - + QPoint curspos = coordconv3_2 (m_hoverpos); - - for (const vertex& pos3d: m_knownVerts) { - QPoint pos2d = coordconv3_2 (pos3d); - + + for (const vertex& pos3d: m_knownVerts) + { QPoint pos2d = coordconv3_2 (pos3d); + // Measure squared distance const double dx = abs (pos2d.x() - curspos.x()), - dy = abs (pos2d.y() - curspos.y()), - distsq = (dx * dx) + (dy * dy); - + dy = abs (pos2d.y() - curspos.y()), + distsq = (dx * dx) + (dy * dy); + if (distsq >= 1024.0f) // 32.0f ** 2 continue; // too far away - - if (distsq < mindist) { - mindist = distsq; + + if (distsq < mindist) + { mindist = distsq; closest = pos3d; valid = true; - - /* If it's only 4 pixels away, I think we found our vertex now. */ + + // If it's only 4 pixels away, I think we found our vertex now. if (distsq <= 16.0f) // 4.0f ** 2 break; } } - + if (valid) addDrawnVertex (closest); } - - if (wasRight && m_drawedVerts.size() > 0) { - // Remove the last vertex - m_drawedVerts.erase (m_drawedVerts.size() - 1); - - if (m_drawedVerts.size() == 0) + + if (wasRight && !m_drawedVerts.isEmpty()) + { // Remove the last vertex + m_drawedVerts.removeLast(); + + if (m_drawedVerts.isEmpty()) m_rectdraw = false; } - + end: update(); m_totalmove = 0; @@ -723,89 +858,89 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::mousePressEvent (QMouseEvent* ev) { - m_totalmove = 0; - - if (ev->modifiers() & Qt::ControlModifier) { - m_rangepick = true; +void GLRenderer::mousePressEvent (QMouseEvent* ev) +{ m_totalmove = 0; + + if (ev->modifiers() & Qt::ControlModifier) + { m_rangepick = true; m_rangeStart.setX (ev->x()); m_rangeStart.setY (ev->y()); m_addpick = (m_keymods & Qt::AltModifier); ev->accept(); } - + m_lastButtons = ev->buttons(); } // ============================================================================= // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ============================================================================= -void GLRenderer::mouseMoveEvent (QMouseEvent* ev) { - int dx = ev->x() - m_pos.x(); +void GLRenderer::mouseMoveEvent (QMouseEvent* ev) +{ int dx = ev->x() - m_pos.x(); int dy = ev->y() - m_pos.y(); m_totalmove += abs (dx) + abs (dy); - + const bool left = ev->buttons() & Qt::LeftButton, - mid = ev->buttons() & Qt::MidButton, - shift = ev->modifiers() & Qt::ShiftModifier; - - if (mid || (left && shift)) { - m_panX += 0.03f * dx * (zoom() / 7.5f); - m_panY -= 0.03f * dy * (zoom() / 7.5f); + mid = ev->buttons() & Qt::MidButton, + shift = ev->modifiers() & Qt::ShiftModifier; + + if (mid || (left && shift)) + { pan (X) += 0.03f * dx * (zoom() / 7.5f); + pan (Y) -= 0.03f * dy * (zoom() / 7.5f); m_panning = true; - } elif (left && !m_rangepick && camera() == Free) { - m_rotX = m_rotX + (dy); - m_rotY = m_rotY + (dx); - - clampAngle (m_rotX); - clampAngle (m_rotY); + } elif (left && !m_rangepick && camera() == Free) + { rot (X) = rot (X) + dy; + rot (Y) = rot (Y) + dx; + + clampAngle (rot (X)); + clampAngle (rot (Y)); } - + // Start the tool tip timer if (!m_drawToolTip) m_toolTipTimer->start (500); - + // Update 2d position m_pos = ev->pos(); m_globalpos = ev->globalPos(); - + // Calculate 3d position of the cursor m_hoverpos = (camera() != Free) ? coordconv2_3 (m_pos, true) : g_origin; - + // Update rect vertices since m_hoverpos may have changed updateRectVerts(); - + update(); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::keyPressEvent (QKeyEvent* ev) { - m_keymods = ev->modifiers(); +void GLRenderer::keyPressEvent (QKeyEvent* ev) +{ m_keymods = ev->modifiers(); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::keyReleaseEvent (QKeyEvent* ev) { - m_keymods = ev->modifiers(); +void GLRenderer::keyReleaseEvent (QKeyEvent* ev) +{ m_keymods = ev->modifiers(); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::wheelEvent (QWheelEvent* ev) { - makeCurrent(); - +void GLRenderer::wheelEvent (QWheelEvent* ev) +{ makeCurrent(); + zoomNotch (ev->delta() > 0); - setZoom (clamp<double> (zoom(), 0.01f, 10000.0f)); - + zoom() = clamp (zoom(), 0.01, 10000.0); + update(); ev->accept(); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::leaveEvent (QEvent* ev) { - (void) ev; +void GLRenderer::leaveEvent (QEvent* ev) +{ (void) ev; m_drawToolTip = false; m_toolTipTimer->stop(); update(); @@ -813,203 +948,188 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::contextMenuEvent (QContextMenuEvent* ev) { - g_win->spawnContextMenu (ev->globalPos()); +void GLRenderer::contextMenuEvent (QContextMenuEvent* ev) +{ g_win->spawnContextMenu (ev->globalPos()); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::setCamera (const GL::Camera cam) { - m_camera = cam; +void GLRenderer::setCamera (const GL::Camera cam) +{ m_camera = cam; gl_camera = (int) cam; g_win->updateEditModeActions(); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::pick (uint mouseX, uint mouseY) { - GLint viewport[4]; +void GLRenderer::pick (int mouseX, int mouseY) +{ GLint viewport[4]; makeCurrent(); - + // Use particularly thick lines while picking ease up selecting lines. glLineWidth (max<double> (gl_linethickness, 6.5f)); - + // Clear the selection if we do not wish to add to it. - if (!m_addpick) { - List<LDObject*> oldsel = g_win->sel(); - g_win->sel().clear(); - - for (LDObject* obj : oldsel) { - obj->setSelected (false); + if (!m_addpick) + { QList<LDObject*> oldsel = selection(); + LDFile::current()->clearSelection(); + + for (LDObject* obj : oldsel) compileObject (obj); - } } - + m_picking = true; - + // Paint the picking scene glDisable (GL_DITHER); glClearColor (1.0f, 1.0f, 1.0f, 1.0f); - + drawGLScene(); - + glGetIntegerv (GL_VIEWPORT, viewport); - - int x0 = mouseX, - y0 = mouseY, - x1, y1; - + + short x0 = mouseX, + y0 = mouseY; + short x1, y1; + // Determine how big an area to read - with range picking, we pick by // the area given, with single pixel picking, we use an 1 x 1 area. - if (m_rangepick) { - x1 = m_rangeStart.x(); + if (m_rangepick) + { x1 = m_rangeStart.x(); y1 = m_rangeStart.y(); - } else { - x1 = x0 + 1; + } + else + { x1 = x0 + 1; y1 = y0 + 1; } - + // x0 and y0 must be less than x1 and y1, respectively. if (x0 > x1) dataswap (x0, x1); - + if (y0 > y1) dataswap (y0, y1); - + // Clamp the values to ensure they're within bounds - x0 = max (0, x0); - y0 = max (0, y0); - x1 = min (x1, m_width); - y1 = min (y1, m_height); - - const int areawidth = (x1 - x0); - const int areaheight = (y1 - y0); - const int64 numpixels = areawidth * areaheight; - + x0 = max<short> (0, x0); + y0 = max<short> (0, y0); + x1 = min<short> (x1, m_width); + y1 = min<short> (y1, m_height); + + const short areawidth = (x1 - x0); + const short areaheight = (y1 - y0); + const long numpixels = areawidth * areaheight; + // Allocate space for the pixel data. uchar* const pixeldata = new uchar[4 * numpixels]; uchar* pixelptr = &pixeldata[0]; - + assert (viewport[3] == m_height); - + // Read pixels from the color buffer. glReadPixels (x0, viewport[3] - y1, areawidth, areaheight, GL_RGBA, GL_UNSIGNED_BYTE, pixeldata); - + LDObject* removedObj = null; - + // Go through each pixel read and add them to the selection. - for (int64 i = 0; i < numpixels; ++i) { - printf ("Color: #%X%X%X\n", pixelptr[0], pixelptr[1], pixelptr[2]); - - int32 idx = - (*(pixelptr + 0) * 0x00001) + - (*(pixelptr + 1) * 0x00100) + - (*(pixelptr + 2) * 0x10000); - + for (long i = 0; i < numpixels; ++i) + { long idx = + (* (pixelptr + 0) * 0x10000) + + (* (pixelptr + 1) * 0x00100) + + (* (pixelptr + 2) * 0x00001); pixelptr += 4; - + if (idx == 0xFFFFFF) continue; // White is background; skip - + LDObject* obj = LDObject::fromID (idx); - if (!obj) { - log ("WARNING: Object #%1 doesn't exist!", idx); - continue; - } - + // If this is an additive single pick and the object is currently selected, // we remove it from selection instead. - if (!m_rangepick && m_addpick) { - bool removed = false; - - for (ulong i = 0; i < g_win->sel().size(); ++i) { - if (g_win->sel()[i] == obj) { - g_win->sel().erase (i); - obj->setSelected (false); - removed = true; - removedObj = obj; - } + if (!m_rangepick && m_addpick) + { if (obj->selected()) + { obj->unselect(); + removedObj = obj; + break; } - - if (removed) - break; } - - g_win->sel() << obj; + + obj->select(); } - + delete[] pixeldata; - - // Remove duplicated entries - g_win->sel().makeUnique(); - + // Update everything now. g_win->updateSelection(); - + // Recompile the objects now to update their color - for (LDObject* obj : g_win->sel()) + for (LDObject* obj : selection()) compileObject (obj); - + if (removedObj) compileObject (removedObj); - + // Restore line thickness glLineWidth (gl_linethickness); - + m_picking = false; m_rangepick = false; glEnable (GL_DITHER); - + setBackground(); repaint(); } // ============================================================================= // ----------------------------------------------------------------------------- -READ_ACCESSOR (EditMode, GLRenderer::editMode) { - return m_editMode; +READ_ACCESSOR (EditMode, GLRenderer::editMode) +{ return m_editMode; } // ============================================================================= // ----------------------------------------------------------------------------- -SET_ACCESSOR (EditMode, GLRenderer::setEditMode) { - m_editMode = val; - - switch (editMode()) { - case Select: - unsetCursor(); - setContextMenuPolicy (Qt::DefaultContextMenu); - break; - - case Draw: - // Cannot draw into the free camera - use top instead. - if (m_camera == Free) - setCamera (Top); - - // Disable the context menu - we need the right mouse button - // for removing vertices. - setContextMenuPolicy (Qt::NoContextMenu); - - // Use the crosshair cursor when drawing. - setCursor (Qt::CrossCursor); - - // Clear the selection when beginning to draw. - // FIXME: make the selection clearing stuff in ::pick a method and use it - // here! This code doesn't update the GL lists. - g_win->sel().clear(); - g_win->updateSelection(); - m_drawedVerts.clear(); - break; +SET_ACCESSOR (EditMode, GLRenderer::setEditMode) +{ m_editMode = val; + + switch (editMode()) + { case Select: + { unsetCursor(); + setContextMenuPolicy (Qt::DefaultContextMenu); + } break; + + case Draw: + case CircleMode: + { // Cannot draw into the free camera - use top instead. + if (m_camera == Free) + setCamera (Top); + + // Disable the context menu - we need the right mouse button + // for removing vertices. + setContextMenuPolicy (Qt::NoContextMenu); + + // Use the crosshair cursor when drawing. + setCursor (Qt::CrossCursor); + + // Clear the selection when beginning to draw. + QList<LDObject*> priorsel = selection(); + LDFile::current()->clearSelection(); + + for (LDObject* obj : priorsel) + compileObject (obj); + + g_win->updateSelection(); + m_drawedVerts.clear(); + } break; } - + g_win->updateEditModeActions(); update(); } // ============================================================================= // ----------------------------------------------------------------------------- -READ_ACCESSOR (LDFile*, GLRenderer::file) { - return m_file; +READ_ACCESSOR (LDFile*, GLRenderer::file) +{ return m_file; } // ============================================================================= @@ -1017,89 +1137,234 @@ SET_ACCESSOR (LDFile*, GLRenderer::setFile) { m_file = val; g_vertexCompiler.setFile (val); - + if (val != null) overlaysFromObjects(); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::endDraw (bool accept) { - (void) accept; - +matrix GLRenderer::getCircleDrawMatrix (double scale) +{ matrix transform = g_circleDrawTransforms[camera() % 3]; + + for (int i = 0; i < 9; ++i) + { if (transform[i] == 2) + transform[i] = scale; + elif (transform[i] == 1 && camera() >= 3) + transform[i] = -1; + } + + return transform; +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void GLRenderer::endDraw (bool accept) +{ (void) accept; + // Clean the selection and create the object - List<vertex>& verts = m_drawedVerts; - LDObject* obj = null; - - if (m_rectdraw) { - LDQuad* quad = new LDQuad; - - // Copy the vertices from m_rectverts - updateRectVerts(); - - for (int i = 0; i < quad->vertices(); ++i) - quad->setVertex (i, m_rectverts[i]); - - quad->setColor (maincolor); - obj = quad; - } else { - switch (verts.size()) { - case 1: - // 1 vertex - add a vertex object - obj = new LDVertex; - static_cast<LDVertex*> (obj)->pos = verts[0]; - obj->setColor (maincolor); - break; - - case 2: - // 2 verts - make a line - obj = new LDLine (verts[0], verts[1]); - obj->setColor (edgecolor); - break; - - case 3: - case 4: - obj = (verts.size() == 3) ? - static_cast<LDObject*> (new LDTriangle) : - static_cast<LDObject*> (new LDQuad); - - obj->setColor (maincolor); - for (ushort i = 0; i < obj->vertices(); ++i) - obj->setVertex (i, verts[i]); - break; + QList<vertex>& verts = m_drawedVerts; + QList<LDObject*> objs; + + switch (editMode()) + { case Draw: + { if (m_rectdraw) + { LDQuad* quad = new LDQuad; + + // Copy the vertices from m_rectverts + updateRectVerts(); + + for (int i = 0; i < quad->vertices(); ++i) + quad->setVertex (i, m_rectverts[i]); + + quad->setColor (maincolor); + objs << quad; + } + else + { switch (verts.size()) + { case 1: + { // 1 vertex - add a vertex object + LDVertex* obj = new LDVertex; + obj->pos = verts[0]; + obj->setColor (maincolor); + objs << obj; + } break; + + case 2: + { // 2 verts - make a line + LDLine* obj = new LDLine (verts[0], verts[1]); + obj->setColor (edgecolor); + objs << obj; + } break; + + case 3: + case 4: + { LDObject* obj = (verts.size() == 3) ? + static_cast<LDObject*> (new LDTriangle) : + static_cast<LDObject*> (new LDQuad); + + obj->setColor (maincolor); + + for (int i = 0; i < obj->vertices(); ++i) + obj->setVertex (i, verts[i]); + + objs << obj; + } break; + } + } + } break; + + case CircleMode: + { const int segs = lores, divs = lores; // TODO: make customizable + double dist0 = circleDrawDist (0), + dist1 = circleDrawDist (1); + LDFile* refFile = null; + matrix transform; + bool circleOrDisc = false; + + if (dist1 < dist0) + std::swap<double> (dist0, dist1); + + if (dist0 == dist1) + { // If the radii are the same, there's no ring space to fill. Use a circle. + refFile = getFile ("4-4edge.dat"); + transform = getCircleDrawMatrix (dist0); + circleOrDisc = true; + } + elif (dist0 == 0 || dist1 == 0) + { // If either radii is 0, use a disc. + refFile = getFile ("4-4disc.dat"); + transform = getCircleDrawMatrix ((dist0 != 0) ? dist0 : dist1); + circleOrDisc = true; + } + elif (g_RingFinder (dist0, dist1)) + { // The ring finder found a solution, use that. Add the component rings to the file. + for (const RingFinder::Component& cmp : g_RingFinder.bestSolution()->components()) + { if ((refFile = getFile (radialFileName (::Ring, lores, lores, cmp.num))) == null) + { refFile = generatePrimitive (::Ring, lores, lores, cmp.num); + refFile->setImplicit (false); + } + + LDSubfile* ref = new LDSubfile; + ref->setFileInfo (refFile); + ref->setTransform (getCircleDrawMatrix (cmp.scale)); + ref->setPosition (m_drawedVerts[0]); + ref->setColor (maincolor); + objs << ref; + } + } + else + { // Last resort: draw the ring with quads + QList<QLineF> c0, c1; + Axis relX, relY, relZ; + getRelativeAxes (relX, relY); + relZ = (Axis) (3 - relX - relY); + double x0 = m_drawedVerts[0][relX], + y0 = m_drawedVerts[0][relY]; + + vertex templ; + templ[relX] = x0; + templ[relY] = y0; + templ[relZ] = depthValue(); + + // Calculate circle coords + makeCircle (segs, divs, dist0, c0); + makeCircle (segs, divs, dist1, c1); + + for (int i = 0; i < segs; ++i) + { vertex v0, v1, v2, v3; + v0 = v1 = v2 = v3 = templ; + v0[relX] += c0[i].x1(); + v0[relY] += c0[i].y1(); + v1[relX] += c0[i].x2(); + v1[relY] += c0[i].y2(); + v2[relX] += c1[i].x2(); + v2[relY] += c1[i].y2(); + v3[relX] += c1[i].x1(); + v3[relY] += c1[i].y1(); + + LDQuad* q = new LDQuad (v0, v1, v2, v3); + q->setColor (maincolor); + + // Ensure the quads always are BFC-front towards the camera + if (camera() % 3 <= 0) + q->invert(); + + objs << q; + } + } + + if (circleOrDisc) + { LDSubfile* ref = new LDSubfile; + ref->setFileInfo (refFile); + ref->setTransform (transform); + ref->setPosition (m_drawedVerts[0]); + ref->setColor (maincolor); + objs << ref; + } + } break; + + case Select: + { assert (false); + return; + } break; + } + + if (objs.size() > 0) + { g_win->beginAction (null); + + for (LDObject* obj : objs) + { file()->addObject (obj); + compileObject (obj); } - } - - if (obj) { - g_win->beginAction (null); - file()->addObject (obj); - compileObject (obj); - g_win->fullRefresh(); + + g_win->refresh(); g_win->endAction(); } - + m_drawedVerts.clear(); m_rectdraw = false; } // ============================================================================= // ----------------------------------------------------------------------------- -static List<vertex> getVertices (LDObject* obj) { - List<vertex> verts; - - if (obj->vertices() >= 2) { - for (int i = 0; i < obj->vertices(); ++i) +double GLRenderer::circleDrawDist (int pos) const +{ assert (m_drawedVerts.size() >= pos + 1); + const vertex& v1 = (m_drawedVerts.size() >= pos + 2) ? m_drawedVerts[pos + 1] : m_hoverpos; + Axis relX, relY; + getRelativeAxes (relX, relY); + + const double dx = m_drawedVerts[0][relX] - v1[relX]; + const double dy = m_drawedVerts[0][relY] - v1[relY]; + return sqrt ((dx * dx) + (dy * dy)); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void GLRenderer::getRelativeAxes (Axis& relX, Axis& relY) const +{ const LDFixedCameraInfo* cam = &g_FixedCameras[m_camera]; + relX = cam->axisX; + relY = cam->axisY; +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +static QList<vertex> getVertices (LDObject* obj) +{ QList<vertex> verts; + + if (obj->vertices() >= 2) + { for (int i = 0; i < obj->vertices(); ++i) verts << obj->getVertex (i); - } elif (obj->getType() == LDObject::Subfile) { - LDSubfile* ref = static_cast<LDSubfile*> (obj); - List<LDObject*> objs = ref->inlineContents (LDSubfile::DeepCacheInline); - - for(LDObject* obj : objs) { - verts << getVertices (obj); + } elif (obj->getType() == LDObject::Subfile) + { LDSubfile* ref = static_cast<LDSubfile*> (obj); + QList<LDObject*> objs = ref->inlineContents (LDSubfile::DeepCacheInline); + + for (LDObject* obj : objs) + { verts << getVertices (obj); delete obj; } } - + return verts; } @@ -1112,30 +1377,30 @@ // ============================================================================= // ----------------------------------------------------------------------------- -uchar* GLRenderer::screencap (ushort& w, ushort& h) { - w = m_width; +uchar* GLRenderer::screencap (int& w, int& h) +{ w = m_width; h = m_height; uchar* cap = new uchar[4 * w * h]; - + m_screencap = true; update(); m_screencap = false; - + // Capture the pixels glReadPixels (0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, cap); - + return cap; } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::slot_toolTipTimer() { - // We come here if the cursor has stayed in one place for longer than a +void GLRenderer::slot_toolTipTimer() +{ // We come here if the cursor has stayed in one place for longer than a // a second. Check if we're holding it over a camera icon - if so, draw // a tooltip. - for (CameraIcon& icon : m_cameraIcons) { - if (icon.destRect.contains (m_pos)) { - m_toolTipCamera = icon.cam; +for (CameraIcon & icon : m_cameraIcons) + { if (icon.destRect.contains (m_pos)) + { m_toolTipCamera = icon.cam; m_drawToolTip = true; update(); break; @@ -1145,226 +1410,238 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::deleteLists (LDObject* obj) { - // Delete the lists but only if they have been initialized +void GLRenderer::deleteLists (LDObject* obj) +{ // Delete the lists but only if they have been initialized if (!obj->m_glinit) return; - - for (const GL::ListType listType : g_glListTypes) + +for (const GL::ListType listType : g_glListTypes) glDeleteLists (obj->glLists[listType], 1); - + obj->m_glinit = false; } // ============================================================================= // ----------------------------------------------------------------------------- -Axis GLRenderer::cameraAxis (bool y, GL::Camera camid) { - if (camid == (GL::Camera) -1) +Axis GLRenderer::cameraAxis (bool y, GL::Camera camid) +{ if (camid == (GL::Camera) - 1) camid = m_camera; - - const staticCameraMeta* cam = &g_staticCameras[camid]; + + const LDFixedCameraInfo* cam = &g_FixedCameras[camid]; return (y) ? cam->axisY : cam->axisX; } // ============================================================================= // ----------------------------------------------------------------------------- -bool GLRenderer::setupOverlay (GL::Camera cam, str file, int x, int y, int w, int h) { - QImage* img = new QImage (file); - overlayMeta& info = getOverlay (cam); - - if (img->isNull()) { - critical (tr ("Failed to load overlay image!")); +bool GLRenderer::setupOverlay (GL::Camera cam, str file, int x, int y, int w, int h) +{ QImage* img = new QImage (file); + LDGLOverlay& info = getOverlay (cam); + + if (img->isNull()) + { critical (tr ("Failed to load overlay image!")); delete img; return false; } - + delete info.img; // delete the old image - + info.fname = file; info.lw = w; info.lh = h; info.ox = x; info.oy = y; info.img = img; - + if (info.lw == 0) info.lw = (info.lh * img->width()) / img->height(); elif (info.lh == 0) info.lh = (info.lw * img->height()) / img->width(); - + const Axis x2d = cameraAxis (false, cam), y2d = cameraAxis (true, cam); - - double negXFac = g_staticCameras[cam].negX ? -1 : 1, - negYFac = g_staticCameras[cam].negY ? -1 : 1; - + const double negXFac = g_FixedCameras[cam].negX ? -1 : 1, + negYFac = g_FixedCameras[cam].negY ? -1 : 1; + info.v0 = info.v1 = g_origin; info.v0[x2d] = - (info.ox * info.lw * negXFac) / img->width(); info.v0[y2d] = (info.oy * info.lh * negYFac) / img->height(); info.v1[x2d] = info.v0[x2d] + info.lw; info.v1[y2d] = info.v0[y2d] + info.lh; - + // Set alpha of all pixels to 0.5 for (long i = 0; i < img->width(); ++i) - for (long j = 0; j < img->height(); ++j) { - uint32 pixel = img->pixel (i, j); - img->setPixel (i, j, 0x80000000 | (pixel & 0x00FFFFFF)); - } - + for (long j = 0; j < img->height(); ++j) + { uint32 pixel = img->pixel (i, j); + img->setPixel (i, j, 0x80000000 | (pixel & 0x00FFFFFF)); + } + updateOverlayObjects(); return true; } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::clearOverlay() { - if (camera() == Free) +void GLRenderer::clearOverlay() +{ if (camera() == Free) return; - - overlayMeta& info = m_overlays[camera()]; + + LDGLOverlay& info = m_overlays[camera()]; delete info.img; info.img = null; - + updateOverlayObjects(); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::setDepthValue (double depth) { - assert (camera() < Free); +void GLRenderer::setDepthValue (double depth) +{ assert (camera() < Free); m_depthValues[camera()] = depth; } // ============================================================================= // ----------------------------------------------------------------------------- -double GLRenderer::depthValue() const { - assert (camera() < Free); +double GLRenderer::depthValue() const +{ assert (camera() < Free); return m_depthValues[camera()]; } // ============================================================================= // ----------------------------------------------------------------------------- -const char* GLRenderer::cameraName() const { - return g_CameraNames[camera()]; +const char* GLRenderer::cameraName() const +{ return g_CameraNames[camera()]; } // ============================================================================= // ----------------------------------------------------------------------------- -overlayMeta& GLRenderer::getOverlay (int newcam) { - return m_overlays[newcam]; +LDGLOverlay& GLRenderer::getOverlay (int newcam) +{ return m_overlays[newcam]; } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::zoomNotch (bool inward) { - if (zoom() > 15) - setZoom (zoom() * (inward ? 0.833f : 1.2f)); +void GLRenderer::zoomNotch (bool inward) +{ if (zoom() > 15) + zoom() *= inward ? 0.833f : 1.2f; else - setZoom (zoom() + (inward ? -1.2f : 1.2f)); + zoom() += inward ? -1.2f : 1.2f; } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::zoomToFit() { - if (file() == null) { - setZoom (30.0f); +void GLRenderer::zoomToFit() +{ if (file() == null || m_width == -1 || m_height == -1) + { zoom() = 30.0f; return; } - + bool lastfilled = false; bool firstrun = true; const uint32 white = 0xFFFFFFFF; bool inward = true; - ulong run = 0; - const ushort w = m_width, h = m_height; - + const int w = m_width, h = m_height; + glClearColor (1.0, 1.0, 1.0, 1.0); glDisable (GL_DITHER); - + // Use the pick list while drawing the scene, this way we can tell whether borders // are background or not. m_picking = true; - - for (;;) { - if (zoom() > 10000.0f || zoom() < 0.0f) { - // Obviously, there's nothing to draw if we get here. + + for (;;) + { if (zoom() > 10000.0 || zoom() < 0.0) + { // Obviously, there's nothing to draw if we get here. // Default to 30.0f and break out. - setZoom (30.0f); + zoom() = 30.0; break; } - + zoomNotch (inward); - + uchar* cap = new uchar[4 * w * h]; drawGLScene(); glReadPixels (0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, cap); uint32* imgdata = reinterpret_cast<uint32*> (cap); bool filled = false; - + // Check the top and bottom rows - for (ushort i = 0; i < w && !filled; ++i) + for (int i = 0; i < w && !filled; ++i) if (imgdata[i] != white || imgdata[((h - 1) * w) + i] != white) filled = true; - + // Left and right edges - for (ushort i = 0; i < h && !filled; ++i) - if (imgdata[i * w] != white || imgdata[(i * w) + (w - 1)] != white) + for (int i = 0; i < h && !filled; ++i) + if (imgdata[i * w] != white || imgdata[(i * w) + w - 1] != white) filled = true; - - if (firstrun) { - // If this is the first run, we don't know enough to determine + + delete[] cap; + + if (firstrun) + { // If this is the first run, we don't know enough to determine // whether the zoom was to fit, so we mark in our knowledge so // far and start over. inward = !filled; firstrun = false; - } else { - // If this run filled the screen and the last one did not, the + } + else + { // If this run filled the screen and the last one did not, the // last run had ideal zoom - zoom a bit back and we should reach it. - if (filled && !lastfilled) { - zoomNotch (false); + if (filled && !lastfilled) + { zoomNotch (false); break; } - + // If this run did not fill the screen and the last one did, we've // now reached ideal zoom so we're done here. if (!filled && lastfilled) break; - + inward = !filled; } - - delete[] cap; + lastfilled = filled; - ++run; } - + setBackground(); m_picking = false; } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::updateRectVerts() { - if (!m_rectdraw) +void GLRenderer::zoomAllToFit() +{ Camera oldcam = camera(); + + for (int i = 0; i < 7; ++i) + { setCamera ((Camera) i); + zoomToFit(); + } + + setCamera (oldcam); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void GLRenderer::updateRectVerts() +{ if (!m_rectdraw) return; - - if (m_drawedVerts.size() == 0) { - for (int i = 0; i < 4; ++i) + + if (m_drawedVerts.isEmpty()) + { for (int i = 0; i < 4; ++i) m_rectverts[i] = m_hoverpos; - + return; } - + vertex v0 = m_drawedVerts[0], - v1 = (m_drawedVerts.size() >= 2) ? m_drawedVerts[1] : m_hoverpos; - + v1 = (m_drawedVerts.size() >= 2) ? m_drawedVerts[1] : m_hoverpos; + const Axis ax = cameraAxis (false), - ay = cameraAxis (true), - az = (Axis) (3 - ax - ay); - + ay = cameraAxis (true), + az = (Axis) (3 - ax - ay); + for (int i = 0; i < 4; ++i) m_rectverts[i][az] = depthValue(); - + m_rectverts[0][ax] = v0[ax]; m_rectverts[0][ay] = v0[ay]; m_rectverts[1][ax] = v1[ax]; @@ -1377,17 +1654,17 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::mouseDoubleClickEvent (QMouseEvent* ev) { - if (!(ev->buttons() & Qt::LeftButton) || editMode() != Select) +void GLRenderer::mouseDoubleClickEvent (QMouseEvent* ev) +{ if (! (ev->buttons() & Qt::LeftButton) || editMode() != Select) return; - + pick (ev->x(), ev->y()); - - if (g_win->sel().size() == 0) + + if (selection().isEmpty()) return; - + g_win->beginAction (null); - LDObject* obj = g_win->sel()[0]; + LDObject* obj = selection().first(); AddObjectDialog::staticDialog (obj->getType(), obj); g_win->endAction(); ev->accept(); @@ -1395,16 +1672,16 @@ // ============================================================================= // ----------------------------------------------------------------------------- -LDOverlay* GLRenderer::findOverlayObject (GLRenderer::Camera cam) { - LDOverlay* ovlobj = null; - - for (LDObject * obj : file()->objects()) { - if (obj->getType() == LDObject::Overlay && static_cast<LDOverlay*> (obj)->camera() == cam) { - ovlobj = static_cast<LDOverlay*> (obj); +LDOverlay* GLRenderer::findOverlayObject (GLRenderer::Camera cam) +{ LDOverlay* ovlobj = null; + + for (LDObject * obj : file()->objects()) + { if (obj->getType() == LDObject::Overlay && static_cast<LDOverlay*> (obj)->camera() == cam) + { ovlobj = static_cast<LDOverlay*> (obj); break; } } - + return ovlobj; } @@ -1412,16 +1689,16 @@ // ----------------------------------------------------------------------------- // Read in overlays from the current file and update overlay info accordingly. // ----------------------------------------------------------------------------- -void GLRenderer::overlaysFromObjects() { - for (Camera cam : g_Cameras) { - if (cam == Free) +void GLRenderer::overlaysFromObjects() +{ for (Camera cam : g_Cameras) + { if (cam == Free) continue; - - overlayMeta& meta = m_overlays[cam]; + + LDGLOverlay& meta = m_overlays[cam]; LDOverlay* ovlobj = findOverlayObject (cam); - - if (!ovlobj && meta.img) { - delete meta.img; + + if (!ovlobj && meta.img) + { delete meta.img; meta.img = null; } elif (ovlobj && (!meta.img || meta.fname != ovlobj->filename())) setupOverlay (cam, ovlobj->filename(), ovlobj->x(), ovlobj->y(), ovlobj->width(), ovlobj->height()); @@ -1430,65 +1707,65 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::updateOverlayObjects() { - for (Camera cam : g_Cameras) { - if (cam == Free) +void GLRenderer::updateOverlayObjects() +{ for (Camera cam : g_Cameras) + { if (cam == Free) continue; - - overlayMeta& meta = m_overlays[cam]; + + LDGLOverlay& meta = m_overlays[cam]; LDOverlay* ovlobj = findOverlayObject (cam); - - if (!meta.img && ovlobj) { - // If this is the last overlay image, we need to remove the empty space after it as well. + + if (!meta.img && ovlobj) + { // If this is the last overlay image, we need to remove the empty space after it as well. LDObject* nextobj = ovlobj->next(); - - if (nextobj && nextobj->getType() == LDObject::Empty) { - m_file->forgetObject (nextobj); + + if (nextobj && nextobj->getType() == LDObject::Empty) + { m_file->forgetObject (nextobj); delete nextobj; } - + // If the overlay object was there and the overlay itself is // not, remove the object. m_file->forgetObject (ovlobj); delete ovlobj; - } elif (meta.img && !ovlobj) { - // Inverse case: image is there but the overlay object is + } elif (meta.img && !ovlobj) + { // Inverse case: image is there but the overlay object is // not, thus create the object. ovlobj = new LDOverlay; - + // Find a suitable position to place this object. We want to place // this into the header, which is everything up to the first scemantic // object. If we find another overlay object, place this object after // the last one found. Otherwise, place it before the first schemantic // object and put an empty object after it (though don't do this if // there was no schemantic elements at all) - ulong i, lastOverlay = -1u; + int i, lastOverlay = -1; bool found = false; - - for (i = 0; i < file()->numObjs(); ++i) { - LDObject* obj = file()->obj (i); - - if (obj->isScemantic()) { - found = true; + + for (i = 0; i < file()->numObjs(); ++i) + { LDObject* obj = file()->obj (i); + + if (obj->isScemantic()) + { found = true; break; } - + if (obj->getType() == LDObject::Overlay) lastOverlay = i; } - - if (lastOverlay != -1u) + + if (lastOverlay != -1) file()->insertObj (lastOverlay + 1, ovlobj); - else { - file()->insertObj (i, ovlobj); - + else + { file()->insertObj (i, ovlobj); + if (found) file()->insertObj (i + 1, new LDEmpty); } } - - if (meta.img && ovlobj) { - ovlobj->setCamera (cam); + + if (meta.img && ovlobj) + { ovlobj->setCamera (cam); ovlobj->setFilename (meta.fname); ovlobj->setX (meta.ox); ovlobj->setY (meta.oy); @@ -1496,8 +1773,7 @@ ovlobj->setHeight (meta.lh); } } - + if (g_win->R() == this) g_win->refresh(); } -#include "moc_gldraw.cpp"