src/glRenderer.cc

changeset 823
1a2f593f0c02
parent 821
a67b1201942a
child 824
6add2126e7ff
--- a/src/glRenderer.cc	Fri Jul 04 00:09:37 2014 +0300
+++ b/src/glRenderer.cc	Fri Jul 04 22:19:01 2014 +0300
@@ -55,15 +55,6 @@
 	{{  0, -1, 0 }, Z, Y, false,  true, true }, // right
 };
 
-// Matrix templates for circle drawing. 2 is substituted with
-// the scale value, 1 is inverted to -1 if needed.
-static const Matrix g_circleDrawMatrixTemplates[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 },
-};
-
 CFGENTRY (String,	backgroundColor,			"#FFFFFF")
 CFGENTRY (String,	mainColor,					"#A0A0A0")
 CFGENTRY (Float,	mainColorAlpha,				1.0)
@@ -75,8 +66,6 @@
 CFGENTRY (Bool,		drawWireframe,				false)
 CFGENTRY (Bool,		useLogoStuds,				false)
 CFGENTRY (Bool,		antiAliasedLines,			true)
-CFGENTRY (Bool,		drawLineLengths,			true)
-CFGENTRY (Bool,		drawAngles,					false)
 CFGENTRY (Bool,		randomColors,				false)
 CFGENTRY (Bool,		highlightObjectBelowCursor,	true)
 CFGENTRY (Bool,		drawSurfaces,				true)
@@ -116,11 +105,10 @@
 //
 GLRenderer::GLRenderer (QWidget* parent) : QGLWidget (parent)
 {
-	m_isPicking = m_rangepick = false;
+	m_isPicking = false;
 	m_camera = (ECamera) cfg::camera;
 	m_drawToolTip = false;
-	m_editMode = ESelectMode;
-	m_rectdraw = false;
+	m_editmode = AbstractEditMode::createByType (EditModeType::Select);
 	m_panning = false;
 	m_compiler = new GLCompiler (this);
 	setDrawOnly (false);
@@ -133,7 +121,6 @@
 	m_thickBorderPen = QPen (QColor (0, 0, 0, 208), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
 	m_thinBorderPen = m_thickBorderPen;
 	m_thinBorderPen.setWidth (1);
-	m_wand = null;
 	setAcceptDrops (true);
 	connect (m_toolTipTimer, SIGNAL (timeout()), this, SLOT (slot_toolTipTimer()));
 
@@ -523,7 +510,7 @@
 	assert (camera() != EFreeCamera);
 
 	Vertex pos3d;
-	const LDFixedCameraInfo* cam = &g_FixedCameras[camera()];
+	const LDFixedCamera* cam = &g_FixedCameras[camera()];
 	const Axis axisX = cam->axisX;
 	const Axis axisY = cam->axisY;
 	const int negXFac = cam->negX ? -1 : 1,
@@ -560,7 +547,7 @@
 QPoint GLRenderer::coordconv3_2 (const Vertex& pos3d) const
 {
 	GLfloat m[16];
-	const LDFixedCameraInfo* cam = &g_FixedCameras[camera()];
+	const LDFixedCamera* cam = &g_FixedCameras[camera()];
 	const Axis axisX = cam->axisX;
 	const Axis axisY = cam->axisY;
 	const int negXFac = cam->negX ? -1 : 1,
@@ -583,6 +570,19 @@
 	return QPoint (rx, -ry);
 }
 
+QPen GLRenderer::textPen() const
+{
+	return QPen (m_darkbg ? Qt::white : Qt::black);
+}
+
+QPen GLRenderer::linePen() const
+{
+	QPen linepen (m_thinBorderPen);
+	linepen.setWidth (2);
+	linepen.setColor (luma (m_bgcolor) < 40 ? Qt::white : Qt::black);
+	return linepen;
+}
+
 // =============================================================================
 //
 void GLRenderer::paintEvent (QPaintEvent*)
@@ -593,8 +593,6 @@
 	initGLData();
 	drawGLScene();
 
-	const QPen textpen (m_darkbg ? Qt::white : Qt::black);
-	const QBrush polybrush (QColor (64, 192, 0, 128));
 	QPainter paint (this);
 	QFontMetrics metrics = QFontMetrics (QFont());
 	paint.setRenderHint (QPainter::HighQualityAntialiasing);
@@ -609,13 +607,13 @@
 		QString text = format ("Rotation: (%1, %2, %3)\nPanning: (%4, %5), Zoom: %6",
 			rot(X), rot(Y), rot(Z), pan(X), pan(Y), zoom());
 		QRect textSize = metrics.boundingRect (0, 0, m_width, m_height, Qt::AlignCenter, text);
-		paint.setPen (textpen);
+		paint.setPen (textPen());
 		paint.drawText ((width() - textSize.width()) / 2, height() - textSize.height(), textSize.width(),
 			textSize.height(), Qt::AlignCenter, text);
 	}
 #endif
 
-	if (camera() != EFreeCamera && !isPicking())
+	if (camera() != EFreeCamera && not isPicking())
 	{
 		// Paint the overlay image if we have one
 		const LDGLOverlay& overlay = currentDocumentData().overlays[camera()];
@@ -634,210 +632,26 @@
 		QString text = format (tr ("X: %1, Y: %2, Z: %3"), m_position3D[X], m_position3D[Y], m_position3D[Z]);
 		QFontMetrics metrics = QFontMetrics (font());
 		QRect textSize = metrics.boundingRect (0, 0, m_width, m_height, Qt::AlignCenter, text);
-		paint.setPen (textpen);
+		paint.setPen (textPen());
 		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);
-
-		// Mode-specific rendering
-		if (editMode() == EDrawMode)
-		{
-			QPoint poly[4];
-			Vertex poly3d[4];
-			int numverts = 4;
-
-			// Calculate polygon data
-			if (not m_rectdraw)
-			{
-				numverts = m_drawedVerts.size() + 1;
-				int i = 0;
-
-				for (Vertex& vert : m_drawedVerts)
-					poly3d[i++] = vert;
-
-				// Draw the cursor vertex as the last one in the list.
-				if (numverts <= 4)
-					poly3d[i] = m_position3D;
-				else
-					numverts = 4;
-			}
-			else
-			{
-				// Get vertex information from m_rectverts
-				if (m_drawedVerts.size() > 0)
-					for (int i = 0; i < numverts; ++i)
-						poly3d[i] = m_rectverts[i];
-				else
-					poly3d[0] = m_position3D;
-			}
-
-			// Convert to 2D
-			for (int i = 0; i < numverts; ++i)
-				poly[i] = coordconv3_2 (poly3d[i]);
-
-			if (numverts > 0)
-			{
-				// Draw the polygon-to-be
-				paint.setBrush (polybrush);
-				paint.drawPolygon (poly, numverts);
-
-				// Draw vertex blips
-				for (int i = 0; i < numverts; ++i)
-				{
-					QPoint& blip = poly[i];
-					paint.setPen (linepen);
-					drawBlip (paint, blip);
-
-					// Draw their coordinates
-					paint.setPen (textpen);
-					paint.drawText (blip.x(), blip.y() - 8, poly3d[i].toString (true));
-				}
-
-				// Draw line lenghts and angle info if appropriate
-				if (numverts >= 2)
-				{
-					int numlines = (m_drawedVerts.size() == 1) ? 1 : m_drawedVerts.size() + 1;
-					paint.setPen (textpen);
-
-					for (int i = 0; i < numlines; ++i)
-					{
-						const int j = (i + 1 < numverts) ? i + 1 : 0;
-						const int h = (i - 1 >= 0) ? i - 1 : numverts - 1;
-
-						if (cfg::drawLineLengths)
-						{
-							const QString label = QString::number ((poly3d[j] - poly3d[i]).length());
-							QPoint origin = QLineF (poly[i], poly[j]).pointAt (0.5).toPoint();
-							paint.drawText (origin, label);
-						}
-
-						if (cfg::drawAngles)
-						{
-							QLineF l0 (poly[h], poly[i]),
-								l1 (poly[i], poly[j]);
-
-							double angle = 180 - l0.angleTo (l1);
-
-							if (angle < 0)
-								angle = 180 - l1.angleTo (l0);
-
-							QString label = QString::number (angle) + QString::fromUtf8 (QByteArray ("\302\260"));
-							QPoint pos = poly[i];
-							pos.setY (pos.y() + metrics.height());
-
-							paint.drawText (pos, label);
-						}
-					}
-				}
-			}
-		}
-		elif (editMode() == ECircleMode)
-		{
-			// 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_position3D));
-			else
-			{
-				QVector<Vertex> verts, verts2;
-				const double dist0 = getCircleDrawDist (0),
-					dist1 = (m_drawedVerts.size() >= 2) ? getCircleDrawDist (1) : -1;
-				const int segs = g_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.setCoordinate (relX, m_drawedVerts[0][relX] + (cos (i * angleUnit) * dist0));
-					v.setCoordinate (relY, m_drawedVerts[0][relY] + (sin (i * angleUnit) * dist0));
-					verts << v;
-
-					if (dist1 != -1)
-					{
-						v.setCoordinate (relX, m_drawedVerts[0][relX] + (cos (i * angleUnit) * dist1));
-						v.setCoordinate (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]);
-					QString label = QString::number (dist0);
-					paint.setPen (textpen);
-					paint.drawText (origin.x() - (metrics.width (label) / 2), origin.y(), label);
-
-					if (m_drawedVerts.size() >= 2)
-					{
-						label = QString::number (dist1);
-						paint.drawText (origin.x() - (metrics.width (label) / 2), origin.y() + metrics.height(), label);
-					}
-				}
-			}
-		}
 	}
 
-	// Camera icons
 	if (not isPicking())
 	{
+		// Draw edit mode HUD
+		m_editmode->render (paint);
+
 		// 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
+		// Draw the camera icons
 		for (CameraIcon& info : m_cameraIcons)
 		{
 			// Don't draw the free camera icon when in draw mode
-			if (&info == &m_cameraIcons[EFreeCamera] && not eq (editMode(), ESelectMode, EMagicWandMode))
+			if (&info == &m_cameraIcons[EFreeCamera] && not m_editmode->allowFreeCamera())
 				continue;
 
 			paint.drawPixmap (info.destRect, *info.img, info.srcRect);
@@ -851,7 +665,7 @@
 
 			QString label;
 			label = format (formatstr, tr (g_CameraNames[camera()]));
-			paint.setPen (textpen);
+			paint.setPen (textPen());
 			paint.drawText (QPoint (margin, height() - (margin + metrics.descent())), label);
 		}
 
@@ -873,7 +687,7 @@
 	{
 		int y = 0;
 		const int margin = 2;
-		QColor penColor = textpen.color();
+		QColor penColor = textPen().color();
 
 		for (const MessageManager::Line& line : messageLog()->getLines())
 		{
@@ -927,39 +741,21 @@
 
 // =============================================================================
 //
-void GLRenderer::addDrawnVertex (Vertex pos)
-{
-	// If we picked an already-existing vertex, stop drawing
-	if (editMode() == EDrawMode)
-	{
-		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) && not (ev->buttons() & Qt::LeftButton),
 	   wasRight = (m_lastButtons & Qt::RightButton) && not (ev->buttons() & Qt::RightButton),
 	   wasMid = (m_lastButtons & Qt::MidButton) && not (ev->buttons() & Qt::MidButton);
 
+	Qt::MouseButtons releasedbuttons = m_lastButtons & ~ev->buttons();
+
 	if (m_panning)
 		m_panning = false;
 
 	if (wasLeft)
 	{
 		// Check if we selected a camera icon
-		if (not m_rangepick)
+		if (m_totalmove < 10)
 		{
 			for (CameraIcon & info : m_cameraIcons)
 			{
@@ -971,35 +767,21 @@
 			}
 		}
 
+		if (not isDrawOnly())
+		{
+			AbstractEditMode::MouseEventData data;
+			data.ev = ev;
+			data.mouseMoved = m_totalmove >= 10;
+			data.keymods = m_keymods;
+			data.releasedButtons = releasedbuttons;
+			m_editmode->mouseReleased (data);
+		}
+
 		switch (editMode())
 		{
 			case EDrawMode:
 			{
-				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);
-						return;
-					}
-
-					if (m_drawedVerts.isEmpty() && ev->modifiers() & Qt::ShiftModifier)
-					{
-						m_rectdraw = true;
-						updateRectVerts();
-					}
-				}
-
-				addDrawnVertex (m_position3D);
+				
 				break;
 			}
 
@@ -1014,35 +796,6 @@
 				addDrawnVertex (m_position3D);
 				break;
 			}
-
-			case ESelectMode:
-			{
-				if (not isDrawOnly())
-				{
-					if (m_totalmove < 10)
-						m_rangepick = false;
-
-					if (not m_rangepick)
-						m_addpick = (m_keymods & Qt::ControlModifier);
-
-					if (m_totalmove < 10 || m_rangepick)
-						pick (ev->x(), ev->y());
-				}
-				break;
-			}
-
-			case EMagicWandMode:
-			{
-				MagicWand::MagicType wandtype = MagicWand::Set;
-
-				if (m_keymods & Qt::ShiftModifier)
-					wandtype = MagicWand::Additive;
-				elif (m_keymods & Qt::ControlModifier)
-					wandtype = MagicWand::Subtractive;
-				
-				m_wand->doMagic (pickOneObject (ev->x(), ev->y()), wandtype);
-				break;
-			}
 		}
 
 		m_rangepick = false;
@@ -1050,55 +803,7 @@
 
 	if (wasMid && editMode() != ESelectMode && m_drawedVerts.size() < 4 && m_totalmove < 10)
 	{
-		// Find the closest vertex to our cursor
-		double			minimumDistance = 1024.0;
-		const Vertex*	closest = null;
-		Vertex			cursorPosition = coordconv2_3 (m_mousePosition, false);
-		QPoint			cursorPosition2D (m_mousePosition);
-		const Axis		relZ = getRelativeZ();
-		QList<Vertex>	vertices;
-
-		for (auto it = document()->vertices().begin(); it != document()->vertices().end(); ++it)
-			vertices << it.key();
-
-		// Sort the vertices in order of distance to camera
-		std::sort (vertices.begin(), vertices.end(), [&](const Vertex& a, const Vertex& b) -> bool
-		{
-			if (g_FixedCameras[camera()].negatedDepth)
-				return a[relZ] > b[relZ];
-
-			return a[relZ] < b[relZ];
-		});
-
-		for (const Vertex& vrt : vertices)
-		{
-			// If the vertex in 2d space is very close to the cursor then we use
-			// it regardless of depth.
-			QPoint vect2d = coordconv3_2 (vrt) - cursorPosition2D;
-			const double distance2DSquared = std::pow (vect2d.x(), 2) + std::pow (vect2d.y(), 2);
-			if (distance2DSquared < 16.0 * 16.0)
-			{
-				closest = &vrt;
-				break;
-			}
-
-			// Check if too far away from the cursor.
-			if (distance2DSquared > 64.0 * 64.0)
-				continue;
-
-			// Not very close to the cursor. Compare using true distance,
-			// including depth.
-			const double distanceSquared = (vrt - cursorPosition).lengthSquared();
-
-			if (distanceSquared < minimumDistance)
-			{
-				minimumDistance = distanceSquared;
-				closest = &vrt;
-			}
-		}
-
-		if (closest != null)
-			addDrawnVertex (*closest);
+		
 	}
 
 	if (wasRight && not m_drawedVerts.isEmpty())
@@ -1120,16 +825,6 @@
 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();
 }
 
@@ -1229,6 +924,10 @@
 //
 void GLRenderer::setCamera (const ECamera cam)
 {
+	// The edit mode may forbid the free camera.
+	if (cam == EFreeCamera && not m_editmode->allowFreeCamera())
+		return;
+
 	m_camera = cam;
 	cfg::camera = (int) cam;
 	g_win->updateEditModeActions();
@@ -1368,55 +1067,17 @@
 
 // =============================================================================
 //
-void GLRenderer::setEditMode (EditMode const& a)
+void GLRenderer::setEditMode (EditModeType a)
 {
-	if (m_editMode == a)
+	if (m_editmode != null && m_editmode->type() == a)
 		return;
 
-	m_editMode = a;
-
-	if (a == EMagicWandMode)
-		m_wand = new MagicWand;
-	else
-	{
-		delete m_wand;
-		m_wand = null;
-	}
-
-	switch (a)
-	{
-		case ESelectMode:
-		case EMagicWandMode:
-		{
-			unsetCursor();
-			setContextMenuPolicy (Qt::DefaultContextMenu);
-		} break;
+	delete m_editmode;
+	m_editmode = AbstractEditMode::createByType (a);
 
-		case EDrawMode:
-		case ECircleMode:
-		{
-			// Cannot draw into the free camera - use top instead.
-			if (camera() == EFreeCamera)
-				setCamera (ETopCamera);
-
-			// 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.
-			LDObjectList priorsel = selection();
-			getCurrentDocument()->clearSelection();
-
-			for (LDObjectPtr obj : priorsel)
-				compileObject (obj);
-
-			g_win->updateSelection();
-			m_drawedVerts.clear();
-		} break;
-	}
+	// If we cannot use the free camera, use the top one instead.
+	if (camera() == EFreeCamera && not m_editmode->allowFreeCamera())
+		setCamera (ETopCamera);
 
 	g_win->updateEditModeActions();
 	update();
@@ -1424,6 +1085,13 @@
 
 // =============================================================================
 //
+EditModeType GLRenderer::currentEditModeType() const
+{
+	return m_editmode->type();
+}
+
+// =============================================================================
+//
 void GLRenderer::setDocument (LDDocumentPtr const& a)
 {
 	m_document = a;
@@ -1467,23 +1135,6 @@
 
 // =============================================================================
 //
-Matrix GLRenderer::getCircleDrawMatrix (double scale)
-{
-	Matrix transform = g_circleDrawMatrixTemplates[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;
@@ -1676,22 +1327,9 @@
 
 // =============================================================================
 //
-double GLRenderer::getCircleDrawDist (int pos) const
-{
-	assert (m_drawedVerts.size() >= pos + 1);
-	Vertex v1 = (m_drawedVerts.size() >= pos + 2) ? m_drawedVerts[pos + 1] : coordconv2_3 (m_mousePosition, false);
-	Axis relX, relY;
-	getRelativeAxes (relX, relY);
-	double dx = m_drawedVerts[0][relX] - v1[relX];
-	double dy = m_drawedVerts[0][relY] - v1[relY];
-	return Grid::snap (sqrt ((dx * dx) + (dy * dy)), Grid::Coordinate);
-}
-
-// =============================================================================
-//
 void GLRenderer::getRelativeAxes (Axis& relX, Axis& relY) const
 {
-	const LDFixedCameraInfo* cam = &g_FixedCameras[camera()];
+	const LDFixedCamera* cam = &g_FixedCameras[camera()];
 	relX = cam->axisX;
 	relY = cam->axisY;
 }
@@ -1700,7 +1338,7 @@
 //
 Axis GLRenderer::getRelativeZ() const
 {
-	const LDFixedCameraInfo* cam = &g_FixedCameras[camera()];
+	const LDFixedCamera* cam = &g_FixedCameras[camera()];
 	return (Axis) (3 - cam->axisX - cam->axisY);
 }
 
@@ -1788,7 +1426,7 @@
 	if (camid == (ECamera) -1)
 		camid = camera();
 
-	const LDFixedCameraInfo* cam = &g_FixedCameras[camid];
+	const LDFixedCamera* cam = &g_FixedCameras[camid];
 	return (y) ? cam->axisY : cam->axisX;
 }
 
@@ -2255,3 +1893,13 @@
 		ev->acceptProposedAction();
 	}
 }
+
+Vertex const& GLRenderer::position3D() const
+{
+	return m_position3D;
+}
+
+LDFixedCamera const& GLRenderer::getFixedCamera (ECamera cam)
+{
+	return g_FixedCameras[cam];
+}

mercurial