src/gldraw.cpp

changeset 665
4355e72ffd47
parent 664
e3a32a79a10a
parent 534
3ed2ebcbc84f
child 666
c595cfb4791c
--- 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"

mercurial