Further work on constrained cameras

Fri, 03 May 2013 03:55:21 +0300

author
Santeri Piippo <crimsondusk64@gmail.com>
date
Fri, 03 May 2013 03:55:21 +0300
changeset 147
291a1fe2d278
parent 146
2ab24976acaa
child 148
ecfbb598db14

Further work on constrained cameras

bbox.cpp file | annotate | diff | comparison | revisions
colors.cpp file | annotate | diff | comparison | revisions
common.h file | annotate | diff | comparison | revisions
file.cpp file | annotate | diff | comparison | revisions
gldraw.cpp file | annotate | diff | comparison | revisions
gldraw.h file | annotate | diff | comparison | revisions
gui.cpp file | annotate | diff | comparison | revisions
gui_actions.cpp file | annotate | diff | comparison | revisions
gui_editactions.cpp file | annotate | diff | comparison | revisions
ldtypes.cpp file | annotate | diff | comparison | revisions
main.cpp file | annotate | diff | comparison | revisions
misc.cpp file | annotate | diff | comparison | revisions
misc.h file | annotate | diff | comparison | revisions
types.cpp file | annotate | diff | comparison | revisions
types.h file | annotate | diff | comparison | revisions
zz_addObjectDialog.cpp file | annotate | diff | comparison | revisions
zz_colorSelectDialog.cpp file | annotate | diff | comparison | revisions
--- a/bbox.cpp	Sun Apr 28 04:04:36 2013 +0300
+++ b/bbox.cpp	Fri May 03 03:55:21 2013 +0300
@@ -21,10 +21,6 @@
 #include "ldtypes.h"
 #include "file.h"
 
-#define CHECK_DIMENSION(V,X) \
-	if (V.X < v0.X) v0.X = V.X; \
-	if (V.X > v1.X) v1.X = V.X;
-
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
@@ -115,26 +111,30 @@
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
 void bbox::calcVertex (vertex v) {
-	CHECK_DIMENSION (v, x)
-	CHECK_DIMENSION (v, y)
-	CHECK_DIMENSION (v, z)
+	for (const Axis ax : g_Axes) {
+		if (v[ax] < v0[ax])
+			v0[ax] = v[ax];
+		
+		if (v[ax] > v1[ax])
+			v1[ax] = v[ax];
+	}
 }
 
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
 void bbox::reset () {
-	v0.x = v0.y = v0.z = +0x7FFFFFFF;
-	v1.x = v1.y = v1.z = -0x7FFFFFFF;
+	v0[X] = v0[Y] = v0[Z] = +0x7FFFFFFF;
+	v1[X] = v1[Y] = v1[Z] = -0x7FFFFFFF;
 }
 
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
 double bbox::size () const {
-	double fXScale = (v0.x - v1.x);
-	double fYScale = (v0.y - v1.y);
-	double fZScale = (v0.z - v1.z);
+	double fXScale = (v0[X] - v1[X]);
+	double fYScale = (v0[Y] - v1[Y]);
+	double fZScale = (v0[Z] - v1[Z]);
 	double fSize = fZScale;
 	
 	if (fXScale > fYScale) {
@@ -152,7 +152,7 @@
 // =============================================================================
 vertex bbox::center () const {
 	return vertex (
-		(v0.x + v1.x) / 2,
-		(v0.y + v1.y) / 2,
-		(v0.z + v1.z) / 2);
+		(v0[X] + v1[X]) / 2,
+		(v0[Y] + v1[Y]) / 2,
+		(v0[Z] + v1[Z]) / 2);
 }
\ No newline at end of file
--- a/colors.cpp	Sun Apr 28 04:04:36 2013 +0300
+++ b/colors.cpp	Fri May 03 03:55:21 2013 +0300
@@ -31,17 +31,19 @@
 	
 	logf ("%s: initializing color information.\n", __func__);
 	
+	color* col;
+	
 	// Always make sure there's 16 and 24 available. They're special like that.
-	color* maincolor = new color;
-	maincolor->zColorString = "#AAAAAA";
-	maincolor->qColor = maincolor->zColorString.chars();
-	maincolor->qEdge = "#000000";
-	g_LDColors[dMainColor] = maincolor;
+	col = new color;
+	col->zColorString = "#AAAAAA";
+	col->qColor = col->zColorString.chars ();
+	col->qEdge = "#000000";
+	g_LDColors[maincolor] = col;
 	
-	color* edgecolor = new color;
-	edgecolor->zColorString = "#000000";
-	edgecolor->qEdge = edgecolor->qColor = edgecolor->zColorString.chars();
-	g_LDColors[dEdgeColor] = edgecolor;
+	col = new color;
+	col->zColorString = "#000000";
+	col->qEdge = col->qColor = col->zColorString.chars ();
+	g_LDColors[edgecolor] = col;
 	
 	parseLDConfig ();
 	
@@ -133,7 +135,7 @@
 		
 		// Don't let LDConfig.ldr override the special colors 16 and 24. However,
 		// do take the name it gives for the color
-		if (dCode == dMainColor || dCode == dEdgeColor) {
+		if (dCode == maincolor || dCode == edgecolor) {
 			g_LDColors[dCode]->zName = zName;
 			continue;
 		}
--- a/common.h	Sun Apr 28 04:04:36 2013 +0300
+++ b/common.h	Fri May 03 03:55:21 2013 +0300
@@ -19,6 +19,16 @@
 #ifndef COMMON_H
 #define COMMON_H
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <vector>
+#include <stdint.h>
+#include <stdarg.h>
+#include "str.h"
+#include "config.h"
+#include "types.h"
+
 #define APPNAME "ldforge"
 #define APPNAME_DISPLAY "LDForge"
 #define APPNAME_CAPS "LDFORGE"
@@ -31,19 +41,7 @@
 // ============---
 // #define RELEASE
 
-#define VERSION_STRING VERSION_MAJOR_STR "." VERSION_MINOR_STR
-
-#define CONFIG_WITH_QT
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <vector>
-#include <stdint.h>
-#include <stdarg.h>
-#include "str.h"
-#include "config.h"
-#include "types.h"
+static const str versionString = format ("%d.%d", VERSION_MAJOR, VERSION_MINOR);
 
 #ifdef __GNUC__
  #define FORMAT_PRINTF(M,N) __attribute__ ((format (printf, M, N)))
@@ -67,8 +65,8 @@
 #define null nullptr
 
 static const double fMaxCoord = 10000.0;
-static const short dMainColor = 16;
-static const short dEdgeColor = 24;
+static const short maincolor = 16;
+static const short edgecolor = 24;
 
 class ForgeWindow;
 class LDObject;
@@ -94,18 +92,27 @@
 #define FVERTEX(V) V.x, V.y, V.z
 
 // -----------------------------------------------------------------------------
-template<class T> inline T clamp (T a, T min, T max) {
+// Templated clamp
+template<class T> static inline T clamp (T a, T min, T max) {
 	return (a > max) ? max : (a < min) ? min : a;
 }
 
-template<class T> inline T min (T a, T b) {
+// Templated minimum
+template<class T> static inline T min (T a, T b) {
 	return (a < b) ? a : b;
 }
 
-template<class T> inline T max (T a, T b) {
+// Templated maximum
+template<class T> static inline T max (T a, T b) {
 	return (a > b) ? a : b;
 }
 
+// Templated absolute value
+template<class T> static inline T abs (T a) {
+	return (a >= 0) ? a : -a;
+}
+
+// Quick QString to const char* conversion
 static inline const char* qchars (QString qstr) {
 	return qstr.toStdString ().c_str ();
 }
@@ -144,7 +151,7 @@
 
 // -----------------------------------------------------------------------------
 // Pointer to the main application.
-extern QApplication* g_qMainApp;
+extern const QApplication* g_qMainApp;
 
 // -----------------------------------------------------------------------------
 // Identity matrix
--- a/file.cpp	Sun Apr 28 04:04:36 2013 +0300
+++ b/file.cpp	Fri May 03 03:55:21 2013 +0300
@@ -368,9 +368,8 @@
 	setlocale (LC_NUMERIC, "C");
 	
 	vertex v;
-	v.x = atof (s[n]);
-	v.y = atof (s[n + 1]);
-	v.z = atof (s[n + 2]);
+	for (const Axis ax : g_Axes)
+		v[ax] = atof (s[n + ax]);
 	
 	return v;
 }
@@ -425,9 +424,9 @@
 					
 					LDVertex* obj = new LDVertex;
 					obj->dColor = atol (tokens[3]);
-					obj->vPosition.x = atof (tokens[4]);
-					obj->vPosition.y = atof (tokens[5]);
-					obj->vPosition.z = atof (tokens[6]);
+					
+					for (const Axis ax : g_Axes)
+						obj->vPosition[ax] = atof (tokens[4 + ax]); // 4 - 6
 					
 					return obj;
 				}
--- a/gldraw.cpp	Sun Apr 28 04:04:36 2013 +0300
+++ b/gldraw.cpp	Fri May 03 03:55:21 2013 +0300
@@ -28,12 +28,25 @@
 #include "gui.h"
 #include "misc.h"
 
-static double g_faObjectOffset[3];
-static double g_StoredBBoxSize;
+static double g_objOffset[3];
+static double g_storedBBoxSize;
+
+static short g_pulseTick = 0;
+static const short g_numPulseTicks = 8;
+static const short g_pulseInterval = 65;
 
-static short g_dPulseTick = 0;
-static const short g_dNumPulseTicks = 8;
-static const short g_dPulseInterval = 65;
+static const struct staticCameraMeta {
+	const char glrotate[3];
+	const Axis axisX, axisY;
+	const bool negX, negY;
+} g_staticCameras[6] = {
+	{ { 0, 0, 0 }, X, Y, false, true },
+	{ { 0, 0, 0 }, X, Y, true, true },
+	{ { 1, 0, 0 }, X, Z, false, false },
+	{ { -1, 0, 0 }, X, Z, false, true },
+	{ { 0, 1, 0 }, Z, Y, true, true },
+	{ { 0, -1, 0 }, Z, Y, false, true },
+};
 
 cfg (str, gl_bgcolor, "#CCCCD9");
 cfg (str, gl_maincolor, "#707078");
@@ -48,6 +61,7 @@
 GLRenderer::GLRenderer (QWidget* parent) : QGLWidget (parent) {
 	resetAngles ();
 	picking = rangepick = false;
+	m_camera = Free;
 	
 	pulseTimer = new QTimer (this);
 	connect (pulseTimer, SIGNAL (timeout ()), this, SLOT (slot_timerUpdate ()));
@@ -65,9 +79,6 @@
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
 void GLRenderer::initializeGL () {
-	glLoadIdentity();
-	glMatrixMode (GL_MODELVIEW);
-	
 	setBackground ();
 	
 	glEnable (GL_POLYGON_OFFSET_FILL);
@@ -98,7 +109,7 @@
 	QColor col (gl_maincolor.value.chars());
 	
 	if (!col.isValid ())
-		return QColor (0, 0, 0); // shouldn't happen
+		return QColor (0, 0, 0);
 	
 	col.setAlpha (gl_maincolor_alpha * 255.f);
 	return col;
@@ -165,7 +176,7 @@
 	}
 #endif
 	
-	if (obj->dColor == dMainColor)
+	if (obj->dColor == maincolor)
 		qCol = getMainColor ();
 	else {
 		color* col = getColor (obj->dColor);
@@ -195,20 +206,20 @@
 	
 	// If it's selected, brighten it up, also pulse flash it if desired.
 	if (g_ForgeWindow->isSelected (obj)) {
-		short dTick, dNumTicks;
+		short tick, numTicks;
 		
 		if (gl_selflash) {
-			dTick = (g_dPulseTick < (g_dNumPulseTicks / 2)) ? g_dPulseTick : (g_dNumPulseTicks - g_dPulseTick);
-			dNumTicks = g_dNumPulseTicks;
+			tick = (g_pulseTick < (g_numPulseTicks / 2)) ? g_pulseTick : (g_numPulseTicks - g_pulseTick);
+			numTicks = g_numPulseTicks;
 		} else {
-			dTick = 2;
-			dNumTicks = 5;
+			tick = 2;
+			numTicks = 5;
 		}
 		
-		const long lAdd = ((dTick * 128) / dNumTicks);
-		r = min (r + lAdd, 255l);
-		g = min (g + lAdd, 255l);
-		b = min (b + lAdd, 255l);
+		const long add = ((tick * 128) / numTicks);
+		r = min (r + add, 255l);
+		g = min (g + add, 255l);
+		b = min (b + add, 255l);
 		
 		// a = 255;
 	}
@@ -250,17 +261,6 @@
 	glMatrixMode (GL_MODELVIEW);
 }
 
-char g_staticCameras[6][3] = {
-	{ 0, 0, 1 },
-	{ 0, 0, -1 },
-	{ 1, 0, 0 },
-	{ -1, 0, 0 },
-	{ 0, 1, 0 },
-	{ 0, -1, 0 },
-};
-
-GLRenderer::Camera cam = GLRenderer::Front;
-
 void GLRenderer::drawGLScene () {
 	if (g_CurrentFile == null)
 		return;
@@ -268,14 +268,22 @@
 	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 	glEnable (GL_DEPTH_TEST);
 	
-	if (cam != GLRenderer::Free) {
+	if (m_camera != GLRenderer::Free) {
 		glMatrixMode (GL_PROJECTION);
 		glPushMatrix ();
 		
 		glLoadIdentity ();
-		glOrtho (-vw, vw, -vh, vh, -100.0, 100.0);
+		glOrtho (-vw, vw, -vh, vh, -100.0f, 100.0f);
 		glTranslatef (panX, panY, 0.0f);
-		glRotatef (90.f, g_staticCameras[cam][0], g_staticCameras[cam][1], g_staticCameras[cam][2]);
+		glRotatef (90.0f, g_staticCameras[m_camera].glrotate[0],
+			g_staticCameras[m_camera].glrotate[1],
+			g_staticCameras[m_camera].glrotate[2]);
+		
+		// Back camera needs to be handled differently
+		if (m_camera == GLRenderer::Back) {
+			glRotatef (180.0f, 1.0f, 0.0f, 0.0f);
+			glRotatef (180.0f, 0.0f, 0.0f, 1.0f);
+		}
 	} else {
 		glMatrixMode (GL_MODELVIEW);
 		glPushMatrix ();
@@ -287,9 +295,10 @@
 		glRotatef (rotY, 0.0f, 1.0f, 0.0f);
 		glRotatef (rotZ, 0.0f, 0.0f, 1.0f);
 	}
-			
-		for (LDObject* obj : g_CurrentFile->objects)
-			glCallList ((picking == false) ? obj->uGLList : obj->uGLPickList);
+	
+	for (LDObject* obj : g_CurrentFile->objects)
+		glCallList (picking == false ? obj->uGLList : obj->uGLPickList);
+	
 	glPopMatrix ();
 	glMatrixMode (GL_MODELVIEW);
 }
@@ -298,22 +307,41 @@
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
 void GLRenderer::paintEvent (QPaintEvent* ev) {
+	Q_UNUSED (ev)
 	drawGLScene ();
 	
+	QPainter paint (this);
 	vw = zoom;
 	vh = (height * vw) / width;
-	const double cx = Grid::snap ((-vw + ((2 * mouseX * vw) / width) - panX) * g_StoredBBoxSize - (g_faObjectOffset[0]), Grid::X);
-	const double cy = Grid::snap ((vh - ((2 * mouseY * vh) / height) - panY) * g_StoredBBoxSize - (g_faObjectOffset[2]), Grid::Z);
 	
-	str text;
-	text.format ("(%.3f, %.3f)", cx, cy);
-	QFontMetrics metrics = QFontMetrics (font ());
-	QRect textSize = metrics.boundingRect (0, 0, width, height, Qt::AlignCenter, text);
-	
-	QPainter paint (this);
-	paint.setRenderHint (QPainter::Antialiasing);
-	paint.drawText (width - textSize.width (), height - 16, textSize.width (),
-		textSize.height (), Qt::AlignCenter, text);
+	if (m_camera != Free) {
+		const staticCameraMeta* cam = &g_staticCameras[m_camera];
+		const Axis axisX = cam->axisX;
+		const Axis axisY = cam->axisY;
+		const short negXFac = cam->negX ? -1 : 1,
+			negYFac = cam->negY ? -1 : 1;
+		
+		double cx = Grid::snap ((-vw + ((2 * mouseX * vw) / width) - panX) * g_storedBBoxSize - (negXFac * g_objOffset[axisX]), (Grid::Config) axisX);
+		double cy = Grid::snap ((vh - ((2 * mouseY * vh) / height) - panY) * g_storedBBoxSize - (negYFac * g_objOffset[axisY]), (Grid::Config) axisY);
+		cx *= negXFac;
+		cy *= negYFac;
+		
+		m_hoverpos = g_Origin;
+		m_hoverpos[axisX] = cx;
+		m_hoverpos[axisY] = cy;
+		
+		paint.setRenderHint (QPainter::Antialiasing);
+		
+		str text;
+		text.format ("X: %s, Y: %s, Z: %s", ftoa (m_hoverpos[X]).chars (),
+			ftoa (m_hoverpos[Y]).chars (), ftoa (m_hoverpos[Z]).chars ());
+		
+		QFontMetrics metrics = QFontMetrics (font ());
+		QRect textSize = metrics.boundingRect (0, 0, width, height, Qt::AlignCenter, text);
+		
+		paint.drawText (width - textSize.width (), height - 16, textSize.width (),
+			textSize.height (), Qt::AlignCenter, text);
+	}
 	
 	// If we're range-picking, draw a rectangle encompassing the selection area.
 	if (rangepick && !picking) {
@@ -332,39 +360,6 @@
 		paint.setPen (borderPen);
 		paint.setBrush (QBrush (fillColor));
 		paint.drawRect (rect);
-		
-#if 0
-		glMatrixMode (GL_PROJECTION);
-		
-		glPushMatrix ();
-			glLoadIdentity ();
-			glOrtho (.0, width, height, .0, -1.0, 1.0);
-			
-			for (int x : {GL_QUADS, GL_LINE_LOOP}) {
-				if (x == GL_QUADS) {
-					// Use a green color when picking additive, a blue color when normally.
-					if (addpick)
-						glColor4f (0.5f, 1.f, 0.f, 0.2f);
-					else
-						glColor4f (0.f, 0.8f, 1.f, 0.2f);
-				} else {
-					if (darkbg)
-						glColor4f (1.f, 1.f, 1.f, 0.7f);
-					else
-						glColor4f (0.f, 0.f, 0.f, 0.7f);
-				}
-				
-				glBegin (x);
-					glVertex2i (x0, y0);
-					glVertex2i (x1, y0);
-					glVertex2i (x1, y1);
-					glVertex2i (x0, y1);
-				glEnd ();
-			}
-		glPopMatrix ();
-		
-		glMatrixMode (GL_MODELVIEW);
-#endif
 	}
 }
 
@@ -374,10 +369,10 @@
 void GLRenderer::compileObjects () {
 	objLists.clear ();
 	
-	g_faObjectOffset[0] = -(g_BBox.v0.x + g_BBox.v1.x) / 2;
-	g_faObjectOffset[1] = -(g_BBox.v0.y + g_BBox.v1.y) / 2;
-	g_faObjectOffset[2] = -(g_BBox.v0.z + g_BBox.v1.z) / 2;
-	g_StoredBBoxSize = g_BBox.size ();
+	g_objOffset[0] = -(g_BBox.v0[X] + g_BBox.v1[X]) / 2;
+	g_objOffset[1] = -(g_BBox.v0[Y] + g_BBox.v1[Y]) / 2;
+	g_objOffset[2] = -(g_BBox.v0[Z] + g_BBox.v1[Z]) / 2;
+	g_storedBBoxSize = g_BBox.size ();
 	
 	if (!g_CurrentFile) {
 		printf ("renderer: no files loaded, cannot compile anything\n");
@@ -517,9 +512,9 @@
 // =============================================================================
 void GLRenderer::compileVertex (vertex& vert) {
 	glVertex3d (
-		(vert.x + g_faObjectOffset[0]) / g_StoredBBoxSize,
-		-(vert.y + g_faObjectOffset[1]) / g_StoredBBoxSize,
-		-(vert.z + g_faObjectOffset[2]) / g_StoredBBoxSize);
+		(vert[X] + g_objOffset[0]) / g_storedBBoxSize,
+		-(vert[Y] + g_objOffset[1]) / g_storedBBoxSize,
+		-(vert[Z] + g_objOffset[2]) / g_storedBBoxSize);
 }
 
 // =============================================================================
@@ -619,8 +614,8 @@
 // =============================================================================
 void GLRenderer::updateSelFlash () {
 	if (gl_selflash && g_ForgeWindow->sel.size() > 0) {
-		pulseTimer->start (g_dPulseInterval);
-		g_dPulseTick = 0;
+		pulseTimer->start (g_pulseInterval);
+		g_pulseTick = 0;
 	} else
 		pulseTimer->stop ();
 }
@@ -775,7 +770,7 @@
 
 // =============================================================================
 void GLRenderer::slot_timerUpdate () {
-	++g_dPulseTick %= g_dNumPulseTicks;
+	++g_pulseTick %= g_numPulseTicks;
 	
 	for (LDObject* obj : g_ForgeWindow->sel)
 		recompileObject (obj);
--- a/gldraw.h	Sun Apr 28 04:04:36 2013 +0300
+++ b/gldraw.h	Fri May 03 03:55:21 2013 +0300
@@ -57,21 +57,16 @@
 	void resetAngles ();
 	uchar* screencap (ushort& w, ushort& h);
 	
-	double rotX, rotY, rotZ;
-	double panX, panY;
-	QPoint pos;
-	double zoom;
+	GLRenderer::Camera camera () { return m_camera; }
+	void setCamera (const GLRenderer::Camera cam) { m_camera = cam; }
+	
 	bool picking;
-	bool rangepick;
-	bool addpick;
 	short width, height;
-	QPoint rangeStart;
 	ushort mouseX, mouseY;
 
 protected:
 	void initializeGL ();
 	void resizeGL (int w, int h);
-	// void paintGL ();
 	
 	void mousePressEvent (QMouseEvent* ev);
 	void mouseMoveEvent (QMouseEvent* ev);
@@ -89,6 +84,11 @@
 	ulong totalmove;
 	bool darkbg;
 	double vw, vh;
+	Camera m_camera;
+	vertex m_hoverpos;
+	double rotX, rotY, rotZ, panX, panY, zoom;
+	bool rangepick, addpick;
+	QPoint pos, rangeStart;
 	
 	void compileOneObject (LDObject* obj);
 	template<class T> void compileSubObject (LDObject* obj, const GLenum eGLType,
--- a/gui.cpp	Sun Apr 28 04:04:36 2013 +0300
+++ b/gui.cpp	Fri May 03 03:55:21 2013 +0300
@@ -474,7 +474,8 @@
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
 void ForgeWindow::setTitle () {
-	str title = APPNAME_DISPLAY " v" VERSION_STRING;
+	str title = APPNAME_DISPLAY " v";
+	title += versionString;
 	
 	// Append our current file if we have one
 	if (g_CurrentFile) {
@@ -675,8 +676,8 @@
 			item->setForeground (0, QColor ("#FFAA00"));
 		} else if (lv_colorize &&
 			obj->dColor != -1 &&
-			obj->dColor != dMainColor &&
-			obj->dColor != dEdgeColor)
+			obj->dColor != maincolor &&
+			obj->dColor != edgecolor)
 		{
 			// If the object isn't in the main or edge color, draw this
 			// list entry in said color.
--- a/gui_actions.cpp	Sun Apr 28 04:04:36 2013 +0300
+++ b/gui_actions.cpp	Fri May 03 03:55:21 2013 +0300
@@ -346,7 +346,7 @@
 	if (root.substr (~root - 4, -1) == ".dat")
 		root -= 4;
 	
-	str defaultname = format ("%s.png", root.chars ());
+	str defaultname = (~root > 0) ? format ("%s.png", root.chars ()) : "";
 	str fname = QFileDialog::getSaveFileName (g_ForgeWindow, "Save Screencap", defaultname,
 		"PNG images (*.png);;JPG images (*.jpg);;BMP images (*.bmp);;All Files (*.*)");
 	
--- a/gui_editactions.cpp	Sun Apr 28 04:04:36 2013 +0300
+++ b/gui_editactions.cpp	Fri May 03 03:55:21 2013 +0300
@@ -303,7 +303,7 @@
 		for (short i = 0; i < dNumLines; ++i) {
 			ulong idx = obj->getIndex (g_CurrentFile) + i + 1;
 			
-			lines[i]->dColor = dEdgeColor;
+			lines[i]->dColor = edgecolor;
 			g_CurrentFile->insertObj (idx, lines[i]);
 			
 			ulaIndices.push_back (idx);
@@ -325,38 +325,18 @@
 	vector<LDObject*> paObjs;
 	
 	for (LDObject* obj : g_ForgeWindow->sel) {
-		vertex* vaCoords = null;
-		ushort uNumCoords = 0;
-		
-		switch (obj->getType ()) {
-		case OBJ_Quad:
-			uNumCoords = 4;
-			vaCoords = static_cast<LDQuad*> (obj)->vaCoords;
-			break;
-		
-		case OBJ_Triangle:
-			uNumCoords = 3;
-			vaCoords = static_cast<LDTriangle*> (obj)->vaCoords;
-			break;
-		
-		case OBJ_Line:
-			uNumCoords = 2;
-			vaCoords = static_cast<LDLine*> (obj)->vaCoords;
-			break;
-		
-		default:
-			break;
-		}
+		if (obj->vertices () < 2)
+			continue;
 		
 		ulong idx = obj->getIndex (g_CurrentFile);
-		for (ushort i = 0; i < uNumCoords; ++i) {
-			LDVertex* pVert = new LDVertex;
-			pVert->vPosition = vaCoords[i];
-			pVert->dColor = obj->dColor;
+		for (short i = 0; i < obj->vertices(); ++i) {
+			LDVertex* vert = new LDVertex;
+			vert->vPosition = obj->vaCoords[i];
+			vert->dColor = obj->dColor;
 			
-			g_CurrentFile->insertObj (++idx, pVert);
+			g_CurrentFile->insertObj (++idx, vert);
 			ulaIndices.push_back (idx);
-			paObjs.push_back (pVert->clone ());
+			paObjs.push_back (vert->clone ());
 		}
 	}
 	
@@ -413,9 +393,9 @@
 	vector<ulong> ulaIndices;
 	
 	// Apply the grid values
-	vVector.x *= currentGrid ().confs[Grid::X]->value;
-	vVector.y *= currentGrid ().confs[Grid::Y]->value;
-	vVector.z *= currentGrid ().confs[Grid::Z]->value;
+	vVector[X] *= currentGrid ().confs[Grid::X]->value;
+	vVector[Y] *= currentGrid ().confs[Grid::Y]->value;
+	vVector[Z] *= currentGrid ().confs[Grid::Z]->value;
 	
 	for (LDObject* obj : g_ForgeWindow->sel) {
 		ulaIndices.push_back (obj->getIndex (g_CurrentFile));
@@ -670,18 +650,10 @@
 MAKE_ACTION (roundCoords, "Round Coordinates", "round-coords", "Round coordinates down to 3/4 decimals", (0)) {
 	setlocale (LC_ALL, "C");
 	
-	for (LDObject* obj : g_ForgeWindow->sel) {
-		for (short i = 0; i < obj->vertices (); ++i) {
-			double* coords[3] = {
-				&obj->vaCoords[i].x,
-				&obj->vaCoords[i].y,
-				&obj->vaCoords[i].z,
-			};
-			
-			for (double* coord : coords)
-				*coord = atof (format ("%.3f", *coord));
-		}
-	}
+	for (LDObject* obj : g_ForgeWindow->sel)
+	for (short i = 0; i < obj->vertices (); ++i)
+	for (const Axis ax : g_Axes)
+		obj->vaCoords[i][ax] = atof (format ("%.3f", obj->vaCoords[i][ax]));
 	
 	g_ForgeWindow->refresh ();
 }
\ No newline at end of file
--- a/ldtypes.cpp	Sun Apr 28 04:04:36 2013 +0300
+++ b/ldtypes.cpp	Fri May 03 03:55:21 2013 +0300
@@ -291,7 +291,7 @@
 		break;
 	}
 	
-	if (obj->dColor == dMainColor)
+	if (obj->dColor == maincolor)
 		obj->dColor = parentcolor;
 }
 
@@ -550,7 +550,7 @@
 				LDLine* pLine = new LDLine;
 				pLine->vaCoords[0] = v0;
 				pLine->vaCoords[1] = v1;
-				pLine->dColor = dEdgeColor;
+				pLine->dColor = edgecolor;
 				pLine->parent = this;
 				
 				paObjects.push_back (pLine);
--- a/main.cpp	Sun Apr 28 04:04:36 2013 +0300
+++ b/main.cpp	Fri May 03 03:55:21 2013 +0300
@@ -29,7 +29,7 @@
 OpenFile* g_CurrentFile = null;
 ForgeWindow* g_ForgeWindow = null; 
 bbox g_BBox;
-QApplication* g_qMainApp = null;
+const QApplication* g_qMainApp = null;
 
 const vertex g_Origin (0.0f, 0.0f, 0.0f);
 const matrix g_mIdentity (1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
@@ -50,7 +50,7 @@
 	initColors ();
 	initPartList ();
 	
-	QApplication app (dArgc, saArgv);
+	const QApplication app (dArgc, saArgv);
 	ForgeWindow* win = new ForgeWindow;
 	
 	g_qMainApp = &app;
--- a/misc.cpp	Sun Apr 28 04:04:36 2013 +0300
+++ b/misc.cpp	Fri May 03 03:55:21 2013 +0300
@@ -21,6 +21,7 @@
 #include <qcolor.h>
 #include "common.h"
 #include "misc.h"
+#include "gui.h"
 
 // Prime number table.
 const ushort g_uaPrimes[NUM_PRIMES] = {
@@ -81,30 +82,29 @@
 // =============================================================================
 // Grid stuff
 cfg (int, grid, Grid::Medium);
+EXTERN_ACTION (gridCoarse)
+EXTERN_ACTION (gridMedium)
+EXTERN_ACTION (gridFine)
 
-cfg (float, grid_coarse_x,		5.0f);
-cfg (float, grid_coarse_y,		5.0f);
-cfg (float, grid_coarse_z,		5.0f);
+cfg (float, grid_coarse_x,			5.0f);
+cfg (float, grid_coarse_y,			5.0f);
+cfg (float, grid_coarse_z,			5.0f);
 cfg (float, grid_coarse_angle,	45.0f);
-cfg (float, grid_medium_x,		1.0f);
-cfg (float, grid_medium_y,		1.0f);
-cfg (float, grid_medium_z,		1.0f);
+cfg (float, grid_medium_x,			1.0f);
+cfg (float, grid_medium_y,			1.0f);
+cfg (float, grid_medium_z,			1.0f);
 cfg (float, grid_medium_angle,	22.5f);
-cfg (float, grid_fine_x,		0.1f);
-cfg (float, grid_fine_y,		0.1f);
-cfg (float, grid_fine_z,		0.1f);
-cfg (float, grid_fine_angle,	7.5f);
+cfg (float, grid_fine_x,			0.1f);
+cfg (float, grid_fine_y,			0.1f);
+cfg (float, grid_fine_z,			0.1f);
+cfg (float, grid_fine_angle,		7.5f);
 
 const gridinfo g_GridInfo[3] = {
-	{ "Coarse",	{ &grid_coarse_x,	&grid_coarse_y,	&grid_coarse_z,	&grid_coarse_angle	} },
-	{ "Medium",	{ &grid_medium_x,	&grid_medium_y,	&grid_medium_z,	&grid_medium_angle	} },
-	{ "Fine",	{ &grid_fine_x,		&grid_fine_y,	&grid_fine_z,	&grid_fine_angle	} }
+	{ "Coarse",	{ &grid_coarse_x,	&grid_coarse_y,	&grid_coarse_z,	&grid_coarse_angle	}, &ACTION (gridCoarse) },
+	{ "Medium",	{ &grid_medium_x,	&grid_medium_y,		&grid_medium_z,		&grid_medium_angle	}, &ACTION (gridMedium) },
+	{ "Fine",		{ &grid_fine_x,	&grid_fine_y,		&grid_fine_z,		&grid_fine_angle	}, &ACTION (gridFine) }
 };
 
-template<class T> inline T abs (T a) {
-	return (a >= 0) ? a : -a;
-}
-
 // =============================================================================
 double Grid::snap (double in, const Grid::Config axis) {
 	const double gridval = currentGrid ().confs[axis]->value;
--- a/misc.h	Sun Apr 28 04:04:36 2013 +0300
+++ b/misc.h	Fri May 03 03:55:21 2013 +0300
@@ -25,6 +25,8 @@
 #define NUM_PRIMES 500
 
 class QColor;
+class QAction;
+
 // Prime numbers
 extern const ushort g_uaPrimes[NUM_PRIMES];
 
@@ -41,6 +43,7 @@
 typedef struct {
 	const char* const name;
 	floatconfig* const confs[4];
+	QAction** const actionptr;
 } gridinfo;
 
 extern_cfg (int, grid);
--- a/types.cpp	Sun Apr 28 04:04:36 2013 +0300
+++ b/types.cpp	Fri May 03 03:55:21 2013 +0300
@@ -8,9 +8,10 @@
 // =============================================================================
 vertex vertex::midpoint (vertex& other) {
 	vertex mid;
-	mid.x = (x + other.x);
-	mid.y = (y + other.y);
-	mid.z = (z + other.z);
+	
+	for (const Axis ax : g_Axes)
+		mid[ax] = (m_coords[ax] + other[ax]) / 2;
+	
 	return mid;
 }
 
@@ -21,9 +22,9 @@
 	const char* fmt = mangled ? "(%s, %s, %s)" : "%s %s %s";
 	
 	return format (fmt,
-		ftoa (x).chars(),
-		ftoa (y).chars(),
-		ftoa (z).chars());
+		ftoa (coord (X)).chars(),
+		ftoa (coord (Y)).chars(),
+		ftoa (coord (Z)).chars());
 }
 
 // =============================================================================
@@ -31,13 +32,13 @@
 // =============================================================================
 void vertex::transform (matrix transmatrx, vertex pos) {
 	double x2, y2, z2;
-	x2 = (transmatrx[0] * x) + (transmatrx[1] * y) + (transmatrx[2] * z) + pos.x;
-	y2 = (transmatrx[3] * x) + (transmatrx[4] * y) + (transmatrx[5] * z) + pos.y;
-	z2 = (transmatrx[6] * x) + (transmatrx[7] * y) + (transmatrx[8] * z) + pos.z;
+	x2 = (transmatrx[0] * coord (X)) + (transmatrx[1] * coord (Y)) + (transmatrx[2] * coord (Z)) + pos[X];
+	y2 = (transmatrx[3] * coord (X)) + (transmatrx[4] * coord (Y)) + (transmatrx[5] * coord (Z)) + pos[Y];
+	z2 = (transmatrx[6] * coord (X)) + (transmatrx[7] * coord (Y)) + (transmatrx[8] * coord (Z)) + pos[Z];
 	
-	x = x2;
-	y = y2;
-	z = z2;
+	coord (X) = x2;
+	coord (Y) = y2;
+	coord (Z) = z2;
 }
 
 // =============================================================================
--- a/types.h	Sun Apr 28 04:04:36 2013 +0300
+++ b/types.h	Fri May 03 03:55:21 2013 +0300
@@ -40,6 +40,9 @@
 
 class matrix;
 
+enum Axis { X, Y, Z };
+static const Axis g_Axes[3] = {X, Y, Z};
+
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
@@ -50,16 +53,19 @@
 // =============================================================================
 class vertex {
 public:
-	double x, y, z;
+	double m_coords[3];
 	
 	vertex () {}
-	vertex (double x, double y, double z) : x (x), y (y), z (z) {}
+	vertex (double x, double y, double z) {
+		m_coords[X] = x;
+		m_coords[Y] = y;
+		m_coords[Z] = z;
+	}
 	
 	// =========================================================================
 	void move (vertex other) {
-		x += other.x;
-		y += other.y;
-		z += other.z;
+		for (const Axis ax : g_Axes)
+			m_coords[ax] += other[ax];
 	}
 	
 	// =========================================================================
@@ -76,20 +82,27 @@
 	
 	// =========================================================================
 	vertex& operator/= (const double d) {
-		x /= d;
-		y /= d;
-		z /= d;
+		for (const Axis ax : g_Axes)
+			m_coords[ax] /= d;
 		return *this;
 	}
 	
 	// =========================================================================
 	vertex operator- () const {
-		return vertex (-x, -y, -z);
+		return vertex (-m_coords[X], -m_coords[Y], -m_coords[Z]);
 	}
 	
 	// =========================================================================
-	double coord (const ushort n) const {
-		return *(&x + n);
+	double& coord (const ushort n) const {
+		return const_cast<double&> (m_coords[n]);
+	}
+	
+	double& operator[] (const Axis ax) const {
+		return coord ((ushort) ax);
+	}
+	
+	double& operator[] (const ushort n) const {
+		return coord (n);
 	}
 	
 	// =========================================================================
--- a/zz_addObjectDialog.cpp	Sun Apr 28 04:04:36 2013 +0300
+++ b/zz_addObjectDialog.cpp	Fri May 03 03:55:21 2013 +0300
@@ -27,11 +27,9 @@
 #include "history.h"
 
 #define APPLY_COORDS(OBJ, N) \
-	for (short i = 0; i < N; ++i) { \
-		OBJ->vaCoords[i].x = dlg.dsb_coords[(i * 3) + 0]->value (); \
-		OBJ->vaCoords[i].y = dlg.dsb_coords[(i * 3) + 1]->value (); \
-		OBJ->vaCoords[i].z = dlg.dsb_coords[(i * 3) + 2]->value (); \
-	}
+	for (short i = 0; i < N; ++i) \
+		for (const Axis ax : g_Axes) \
+			OBJ->vaCoords[i][ax] = dlg.dsb_coords[(i * 3) + ax]->value ();
 
 // =============================================================================
 class SubfileListItem : public QTreeWidgetItem {
@@ -170,7 +168,7 @@
 	
 	// Show a color edit dialog for the types that actually use the color
 	if (defaults->isColored ()) {
-		dColor = (type == OBJ_CondLine || type == OBJ_Line) ? dEdgeColor : dMainColor;
+		dColor = (type == OBJ_CondLine || type == OBJ_Line) ? edgecolor : maincolor;
 		
 		pb_color = new QPushButton;
 		setButtonBackground (pb_color, dColor);
@@ -364,9 +362,9 @@
 		{
 			LDVertex* vert = initObj<LDVertex> (obj);
 			vert->dColor = dlg.dColor;
-			vert->vPosition.x = dlg.dsb_coords[0]->value ();
-			vert->vPosition.y = dlg.dsb_coords[1]->value ();
-			vert->vPosition.z = dlg.dsb_coords[2]->value ();
+			
+			for (const Axis ax : g_Axes)
+				vert->vPosition[ax] = dlg.dsb_coords[ax]->value ();
 		}
 		break;
 	
@@ -374,9 +372,10 @@
 		{
 			LDRadial* pRad = initObj<LDRadial> (obj);
 			pRad->dColor = dlg.dColor;
-			pRad->vPosition.x = dlg.dsb_coords[0]->value ();
-			pRad->vPosition.y = dlg.dsb_coords[1]->value ();
-			pRad->vPosition.z = dlg.dsb_coords[2]->value ();
+			
+			for (const Axis ax : g_Axes)
+				pRad->vPosition[ax] = dlg.dsb_coords[ax]->value ();
+			
 			pRad->dDivisions = (dlg.cb_radHiRes->checkState () != Qt::Checked) ? 16 : 48;
 			pRad->dSegments = min<short> (dlg.sb_radSegments->value (), pRad->dDivisions);
 			pRad->eRadialType = (LDRadial::Type) dlg.bb_radType->value ();
@@ -393,9 +392,10 @@
 			
 			LDSubfile* ref = initObj<LDSubfile> (obj);
 			ref->dColor = dlg.dColor;
-			ref->vPosition.x = dlg.dsb_coords[0]->value ();
-			ref->vPosition.y = dlg.dsb_coords[1]->value ();
-			ref->vPosition.z = dlg.dsb_coords[2]->value ();
+			
+			for (const Axis ax : g_Axes)
+				ref->vPosition[ax] = dlg.dsb_coords[ax]->value ();
+			
 			ref->zFileName = name;
 			ref->mMatrix = g_mIdentity;
 			ref->pFile = loadSubfile (name);
--- a/zz_colorSelectDialog.cpp	Sun Apr 28 04:04:36 2013 +0300
+++ b/zz_colorSelectDialog.cpp	Fri May 03 03:55:21 2013 +0300
@@ -110,7 +110,7 @@
 		
 		QColor qColor = meta->qColor;
 		
-		if (i == dMainColor) {
+		if (i == maincolor) {
 			// Use the user preferences for main color here
 			qColor = gl_maincolor.value.chars ();
 			qColor.setAlpha (gl_maincolor_alpha * 255.0f);

mercurial