Merge branch 'master' into gl

Wed, 23 Oct 2013 12:46:10 +0300

author
Santeri Piippo <crimsondusk64@gmail.com>
date
Wed, 23 Oct 2013 12:46:10 +0300
changeset 665
4355e72ffd47
parent 664
e3a32a79a10a (diff)
parent 537
1add0ee96fb3 (current diff)
child 666
c595cfb4791c

Merge branch 'master' into gl

Conflicts:
src/file.cpp
src/gldraw.cpp
src/gldraw.h
src/gui.cpp
src/ldtypes.cpp
src/src.pro
src/types.h

icons/visibility.png file | annotate | diff | comparison | revisions
ldforge.pro file | annotate | diff | comparison | revisions
legacy/checkboxgroup.cpp file | annotate | diff | comparison | revisions
src/file.cpp file | annotate | diff | comparison | revisions
src/gldraw.cpp file | annotate | diff | comparison | revisions
src/gldraw.h file | annotate | diff | comparison | revisions
src/gui.cpp file | annotate | diff | comparison | revisions
src/ldtypes.cpp file | annotate | diff | comparison | revisions
src/src.pro file | annotate | diff | comparison | revisions
src/types.h file | annotate | diff | comparison | revisions
--- a/src/file.cpp	Tue Oct 22 22:14:32 2013 +0300
+++ b/src/file.cpp	Wed Oct 23 12:46:10 2013 +0300
@@ -33,6 +33,7 @@
 #include "history.h"
 #include "dialogs.h"
 #include "gldraw.h"
+#include "gldata.h"
 #include "moc_file.cpp"
 
 cfg (String, io_ldpath, "");
@@ -297,7 +298,6 @@
 
 		// Trim the trailing newline
 		qchar c;
-
 		while (!line.isEmpty() && ((c = line[line.length() - 1]) == '\n' || c == '\r'))
 			line.chop (1);
 
@@ -1110,6 +1110,7 @@
 		g_win->updateFileListItem (f);
 		g_win->buildObjList();
 		g_win->updateTitle();
+		g_vertexCompiler.needMerge();
 		g_win->R()->setFile (f);
 		g_win->R()->resetAllAngles();
 		g_win->R()->repaint();
@@ -1190,4 +1191,4 @@
 // -----------------------------------------------------------------------------
 const QList<LDObject*>& LDFile::selection() const
 {	return m_sel;
-}
\ No newline at end of file
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gldata.cpp	Wed Oct 23 12:46:10 2013 +0300
@@ -0,0 +1,461 @@
+#include "gldata.h"
+#include "ldtypes.h"
+#include "colors.h"
+#include "file.h"
+#include "misc.h"
+#include "gldraw.h"
+#include <QDate>
+
+cfg (Bool, gl_blackedges, false);
+static List<short> g_warnedColors;
+VertexCompiler g_vertexCompiler;
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+VertexCompiler::Array::Array() :
+	m_data (null)
+{
+	clear();
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+VertexCompiler::Array::~Array() {
+	delete[] m_data;
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+void VertexCompiler::Array::clear() {
+	delete[] m_data;
+	
+	m_data = new Vertex[64];
+	m_size = 64;
+	m_ptr = &m_data[0];
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+void VertexCompiler::Array::resizeToFit (Size newSize) {
+	if (allocatedSize() >= newSize)
+		return;
+	
+	int32 cachedWriteSize = writtenSize();
+	
+	// Add some lee-way space to reduce the amount of resizing.
+	newSize += 256;
+	
+	const Size oldSize = allocatedSize();
+	
+	// We need to back up the data first
+	Vertex* copy = new Vertex[oldSize];
+	memcpy (copy, m_data, oldSize);
+	
+	// Re-create the buffer
+	delete[] m_data;
+	m_data = new Vertex[newSize];
+	m_size = newSize;
+	m_ptr = &m_data[cachedWriteSize / sizeof (Vertex)];
+	
+	// Copy the data back
+	memcpy (m_data, copy, oldSize);
+	delete[] copy;
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+const VertexCompiler::Vertex* VertexCompiler::Array::data() const {
+	return m_data;
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+const VertexCompiler::Array::Size& VertexCompiler::Array::allocatedSize() const {
+	return m_size;
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+VertexCompiler::Array::Size VertexCompiler::Array::writtenSize() const {
+	return (m_ptr - m_data) * sizeof (Vertex);
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+void VertexCompiler::Array::write (const Vertex& f) {
+	// Ensure there's enoughspace for the new vertex
+	resizeToFit (writtenSize() + sizeof f);
+	
+	// Write the float in
+	*m_ptr++ = f;
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+void VertexCompiler::Array::merge (Array* other) {
+	// Ensure there's room for both buffers
+	resizeToFit (writtenSize() + other->writtenSize());
+	
+	memcpy (m_ptr, other->data(), other->writtenSize());
+	m_ptr += other->writtenSize() / sizeof (Vertex);
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+VertexCompiler::VertexCompiler() :
+	m_file (null)
+{
+	needMerge();
+}
+
+VertexCompiler::~VertexCompiler() {}
+
+// =============================================================================
+// Note: we use the top level object's color but the draw object's vertices.
+// This is so that the index color is generated correctly - it has to reference
+// the top level object's ID. This is crucial for picking to work.
+// -----------------------------------------------------------------------------
+void VertexCompiler::compilePolygon (LDObject* drawobj, LDObject* trueobj, List<CompiledTriangle>& data) {
+	const QColor pickColor = getObjectColor (trueobj, PickColor);
+	LDObject::Type type = drawobj->getType();
+	List<LDObject*> objs;
+	
+	assert (type != LDObject::Subfile);
+	
+	if (type == LDObject::Quad) {
+		for (LDTriangle* t : static_cast<LDQuad*> (drawobj)->splitToTriangles())
+			objs << t;
+	} else
+		objs << drawobj;
+	
+	for (LDObject* obj : objs) {
+		const LDObject::Type objtype = obj->getType();
+		const bool isline = (objtype == LDObject::Line || objtype == LDObject::CndLine);
+		const int verts = isline ? 2 : obj->vertices();
+		QColor normalColor = getObjectColor (obj, Normal);
+		
+		assert (isline || objtype == LDObject::Triangle);
+		
+		CompiledTriangle a;
+		a.rgb = normalColor.rgb();
+		a.pickrgb = pickColor.rgb();
+		a.numVerts = verts;
+		a.obj = trueobj;
+		a.isCondLine = (objtype == LDObject::CndLine);
+		
+		for (int i = 0; i < verts; ++i) {
+			a.verts[i] = obj->getVertex (i);
+			a.verts[i].y() = -a.verts[i].y();
+			a.verts[i].z() = -a.verts[i].z();
+		}
+		
+		data << a;
+	}
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+void VertexCompiler::compileObject (LDObject* obj) {
+	initObject (obj);
+	List<CompiledTriangle> data;
+	QTime t0;
+	
+	for (int i = 0; i < GL::NumArrays; ++i)
+		m_objArrays[obj][i].clear();
+	
+	t0 = QTime::currentTime();
+	compileSubObject (obj, obj, data);
+	print ("COMPILATION: %1ms\n", t0.msecsTo (QTime::currentTime()));
+	
+	t0 = QTime::currentTime();
+	for (int i = 0; i < GL::NumArrays; ++i) {
+		GL::VAOType type = (GL::VAOType) i;
+		const bool islinearray = (type == GL::EdgeArray || type == GL::EdgePickArray);
+		
+		for (const CompiledTriangle& poly : data) {
+			if (poly.isCondLine) {
+				// Conditional lines go to the edge pick array and the array
+				// specifically designated for conditional lines and nowhere else.
+				if (type != GL::EdgePickArray && type != GL::CondEdgeArray)
+					continue;
+			} else {
+				// Lines and only lines go to the line array and only to the line array.
+				if ((poly.numVerts == 2) ^ islinearray)
+					continue;
+				
+				// Only conditional lines go into the conditional line array
+				if (type == GL::CondEdgeArray)
+					continue;
+			}
+			
+			Array* verts = postprocess (poly, type);
+			m_objArrays[obj][type].merge (verts);
+			delete verts;
+		}
+	}
+	print ("POST-PROCESS: %1ms\n", t0.msecsTo (QTime::currentTime()));
+	
+	needMerge();
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+void VertexCompiler::compileSubObject (LDObject* obj, LDObject* topobj, List<CompiledTriangle>& data) {
+	List<LDObject*> objs;
+	
+	switch (obj->getType()) {
+	case LDObject::Triangle:
+	case LDObject::Line:
+	case LDObject::CndLine:
+		compilePolygon (obj, topobj, data);
+		break;
+	
+	case LDObject::Quad:
+		for (LDTriangle* triangle : static_cast<LDQuad*> (obj)->splitToTriangles())
+			compilePolygon (triangle, topobj, data);
+		break;
+	
+	case LDObject::Subfile:
+	{
+		QTime t0 = QTime::currentTime();
+		objs = static_cast<LDSubfile*> (obj)->inlineContents (LDSubfile::RendererInline | LDSubfile::DeepCacheInline);
+		print ("\t- INLINE: %1ms\n", t0.msecsTo (QTime::currentTime()));
+		print ("\t- %1 objects\n", objs.size());
+		
+		t0 = QTime::currentTime();
+		for (LDObject* obj : objs) {
+			compileSubObject (obj, topobj, data);
+			delete obj;
+		}
+		print ("\t- SUB-COMPILATION: %1ms\n", t0.msecsTo (QTime::currentTime()));
+	}
+		break;
+	
+	default:
+		break;
+	}
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+void VertexCompiler::compileFile() {
+	for (LDObject* obj : m_file->objects())
+		compileObject (obj);
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+void VertexCompiler::forgetObject (LDObject* obj) {
+	auto it = m_objArrays.find (obj);
+	if (it != m_objArrays.end())
+		delete *it;
+	
+	m_objArrays.remove (obj);
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+void VertexCompiler::setFile (LDFile* file) {
+	m_file = file;
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+const VertexCompiler::Array* VertexCompiler::getMergedBuffer (GL::VAOType type) {
+	// If there are objects staged for compilation, compile them now.
+	if (m_staged.size() > 0) {
+		for (LDObject* obj : m_staged)
+			compileObject (obj);
+		
+		m_staged.clear();
+	}
+	
+	assert (type < GL::NumArrays);
+	
+	if (m_changed[type]) {
+		m_changed[type] = false;
+		m_mainArrays[type].clear();
+		
+		for (LDObject* obj : m_file->objects()) {
+			if (!obj->isScemantic())
+				continue;
+			
+			auto it = m_objArrays.find (obj);
+			
+			if (it != m_objArrays.end())
+				m_mainArrays[type].merge (&(*it)[type]);
+		}
+		
+		print ("merged array %1: %2 bytes\n", (int) type, m_mainArrays[type].writtenSize());
+	}
+	
+	return &m_mainArrays[type];
+}
+
+// =============================================================================
+// This turns a compiled triangle into usable VAO vertices
+// -----------------------------------------------------------------------------
+VertexCompiler::Array* VertexCompiler::postprocess (const CompiledTriangle& triangle, GL::VAOType type) {
+	Array* va = new Array;
+	List<Vertex> verts;
+	
+	for (int i = 0; i < triangle.numVerts; ++i) {
+		alias v0 = triangle.verts[i];
+		Vertex v;
+		v.x = v0.x();
+		v.y = v0.y();
+		v.z = v0.z();
+		
+		switch (type) {
+		case GL::MainArray:
+		case GL::EdgeArray:
+		case GL::CondEdgeArray:
+			v.color = triangle.rgb;
+			break;
+		
+		case GL::PickArray:
+		case GL::EdgePickArray:
+			v.color = triangle.pickrgb;
+		
+		case GL::BFCArray:
+			break; // handled separately
+		
+		case GL::NumArrays:
+			assert (false);
+		}
+		
+		verts << v;
+	}
+	
+	if (type == GL::BFCArray) {
+		int32 rgb = getObjectColor (triangle.obj, BFCFront).rgb();
+		for (Vertex v : verts) {
+			v.color = rgb;
+			va->write (v);
+		}
+		
+		rgb = getObjectColor (triangle.obj, BFCBack).rgb();
+		for (Vertex v : c_rev<Vertex> (verts)) {
+			v.color = rgb;
+			va->write (v);
+		}
+	} else {
+		for (Vertex v : verts)
+			va->write (v);
+	}
+	
+	return va;
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+uint32 VertexCompiler::getColorRGB (QColor& color) {
+	return
+		(color.red()   & 0xFF) << 0x00 |
+		(color.green() & 0xFF) << 0x08 |
+		(color.blue()  & 0xFF) << 0x10 |
+		(color.alpha() & 0xFF) << 0x18;
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+QColor VertexCompiler::getObjectColor (LDObject* obj, ColorType colotype) const {
+	QColor qcol;
+	
+	if (!obj->isColored())
+		return QColor();
+	
+	if (colotype == PickColor) {
+		// Make the color by the object's ID if we're picking, so we can make the
+		// ID again from the color we get from the picking results. Be sure to use
+		// the top level parent's index since we want a subfile's children point
+		// to the subfile itself.
+		long i = obj->topLevelParent()->id();
+		
+		// Calculate a color based from this index. This method caters for
+		// 16777216 objects. I don't think that'll be exceeded anytime soon. :)
+		// ATM biggest is 53588.dat with 12600 lines.
+		int r = (i / (256 * 256)) % 256,
+			g = (i / 256) % 256,
+			b = i % 256;
+		
+		return QColor (r, g, b);
+	}
+	
+	if ((colotype == BFCFront || colotype == BFCBack) &&
+		obj->getType() != LDObject::Line &&
+		obj->getType() != LDObject::CndLine) {
+		
+		if (colotype == BFCFront)
+			qcol = QColor (40, 192, 0);
+		else
+			qcol = QColor (224, 0, 0);
+	} else {
+		if (obj->color() == maincolor)
+			qcol = GL::getMainColor();
+		else {
+			LDColor* col = getColor (obj->color());
+			
+			if (col)
+				qcol = col->faceColor;
+		}
+		
+		if (obj->color() == edgecolor) {
+			qcol = QColor (32, 32, 32); // luma (m_bgcolor) < 40 ? QColor (64, 64, 64) : Qt::black;
+			LDColor* col;
+			
+			if (!gl_blackedges && obj->parent() && (col = getColor (obj->parent()->color())))
+				qcol = col->edgeColor;
+		}
+		
+		if (qcol.isValid() == false) {
+			// The color was unknown. Use main color to make the object at least
+			// not appear pitch-black.
+			if (obj->color() != edgecolor)
+				qcol = GL::getMainColor();
+			else
+				qcol = Qt::black;
+			
+			// Warn about the unknown color, but only once.
+			for (short i : g_warnedColors)
+				if (obj->color() == i)
+					return qcol;
+			
+			log ("%1: Unknown color %2!\n", __func__, obj->color());
+			g_warnedColors << obj->color();
+			return qcol;
+		}
+	}
+	
+	if (obj->topLevelParent()->selected()) {
+		// Brighten it up if selected.
+		const int add = 51;
+		
+		qcol.setRed (min (qcol.red() + add, 255));
+		qcol.setGreen (min (qcol.green() + add, 255));
+		qcol.setBlue (min (qcol.blue() + add, 255));
+	}
+	
+	return qcol;
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+void VertexCompiler::needMerge() {
+	// Set all of m_changed to true
+	memset (m_changed, 0xFF, sizeof m_changed);
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+void VertexCompiler::initObject (LDObject* obj) {
+	if (m_objArrays.find (obj) == m_objArrays.end())
+		m_objArrays[obj] = new Array[GL::NumArrays];
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+void VertexCompiler::stageForCompilation (LDObject* obj) {
+	m_staged << obj;
+	m_staged.makeUnique();
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gldata.h	Wed Oct 23 12:46:10 2013 +0300
@@ -0,0 +1,116 @@
+#ifndef LDFORGE_GLDATA_H
+#define LDFORGE_GLDATA_H
+
+#include "types.h"
+#include "gldraw.h"
+#include <QMap>
+#include <QRgb>
+
+class QColor;
+class LDTriangle;
+class LDFile;
+
+/* =============================================================================
+ * -----------------------------------------------------------------------------
+ * VertexCompiler
+ *
+ * This class manages vertex arrays for the GL renderer, compiling vertices into
+ * VAO-readable triangles which can be requested with getMergedBuffer.
+ *
+ * There are 5 main array types:
+ * - the normal polygon array, for triangles
+ * - edge line array, for lines
+ * - BFC array, this is the same as the normal polygon array except that the
+ * -     polygons are listed twice, once normally and green and once reversed
+ * -     and red, this allows BFC red/green view.
+ * - Picking array, this is the samea s the normal polygon array except the
+ * -     polygons are compiled with their index color, this way the picking
+ * -     method is capable of determining which object was selected by pixel
+ * -     color.
+ * - Edge line picking array, the pick array version of the edge line array.
+ *
+ * There are also these same 5 arrays for every LDObject compiled. The main
+ * arrays are generated on demand from the ones in the current file's
+ * LDObjects and stored in cache for faster rendering.
+ *
+ * The nested Array class contains a vector-like buffer of the Vertex structs,
+ * these structs are the VAOs that get passed to the renderer.
+ */
+
+class VertexCompiler {
+public:
+	enum ColorType {
+		Normal,
+		BFCFront,
+		BFCBack,
+		PickColor,
+	};
+	
+	struct CompiledTriangle {
+		vertex    verts[3];
+		uint8     numVerts;    // 2 if a line
+		QRgb      rgb;         // Color of this poly normally
+		QRgb      pickrgb;     // Color of this poly while picking
+		bool      isCondLine;  // Is this a conditional line?
+		LDObject* obj;         // Pointer to the object this poly represents
+	};
+	
+	struct Vertex {
+		float x, y, z;
+		uint32 color;
+		float pad[4];
+	};
+	
+	class Array {
+	public:
+		typedef int32 Size;
+		
+		Array();
+		Array (const Array& other) = delete;
+		~Array();
+		
+		void clear();
+		void merge (Array* other);
+		void resizeToFit (Size newSize);
+		const Size& allocatedSize() const;
+		Size writtenSize() const;
+		const Vertex* data() const;
+		void write (const VertexCompiler::Vertex& f);
+		Array& operator= (const Array& other) = delete;
+		
+	private:
+		Vertex* m_data;
+		Vertex* m_ptr;
+		Size m_size;
+	};
+	
+	VertexCompiler();
+	~VertexCompiler();
+	void setFile (LDFile* file);
+	void compileFile();
+	void forgetObject (LDObject* obj);
+	void initObject (LDObject* obj);
+	const Array* getMergedBuffer (GL::VAOType type);
+	QColor getObjectColor (LDObject* obj, ColorType list) const;
+	void needMerge();
+	void stageForCompilation (LDObject* obj);
+	
+	static uint32 getColorRGB (QColor& color);
+	
+private:
+	void compilePolygon (LDObject* drawobj, LDObject* trueobj, List<CompiledTriangle>& data);
+	void compileObject (LDObject* obj);
+	void compileSubObject (LDObject* obj, LDObject* topobj, List<CompiledTriangle>& data);
+	Array* postprocess (const CompiledTriangle& i, GL::VAOType type);
+	
+	QMap<LDObject*, Array*> m_objArrays;
+	QMap<LDFile*, Array*> m_fileCache;
+	Array m_mainArrays[GL::NumArrays];
+	LDFile* m_file;
+	bool m_changed[GL::NumArrays];
+	List<LDObject*> m_staged;
+};
+
+extern VertexCompiler g_vertexCompiler;
+
+#endif // LDFORGE_GLDATA_H
\ No newline at end of file
--- a/src/gldraw.cpp	Tue Oct 22 22:14:32 2013 +0300
+++ b/src/gldraw.cpp	Wed Oct 23 12:46:10 2013 +0300
@@ -24,7 +24,6 @@
 #include <QToolTip>
 #include <QTimer>
 #include <GL/glu.h>
-
 #include "common.h"
 #include "config.h"
 #include "file.h"
@@ -36,6 +35,7 @@
 #include "dialogs.h"
 #include "addObjectDialog.h"
 #include "messagelog.h"
+#include "gldata.h"
 #include "primitives.h"
 #include "moc_gldraw.cpp"
 
@@ -60,7 +60,6 @@
 cfg (Int, gl_linethickness, 2);
 cfg (Bool, gl_colorbfc, false);
 cfg (Int, gl_camera, GLRenderer::Free);
-cfg (Bool, gl_blackedges, false);
 cfg (Bool, gl_axes, false);
 cfg (Bool, gl_wireframe, false);
 cfg (Bool, gl_logostuds, false);
@@ -96,9 +95,6 @@
 	{ QColor (0,   160, 192), vertex (0, 0, 10000) },
 };
 
-static bool g_glInvert = false;
-static QList<short> g_warnedColors;
-
 // =============================================================================
 // -----------------------------------------------------------------------------
 GLRenderer::GLRenderer (QWidget* parent) : QGLWidget (parent)
@@ -225,11 +221,13 @@
 {	setBackground();
 
 	glLineWidth (gl_linethickness);
+	glLineStipple (1, 0x6666);
 
 	setAutoFillBackground (false);
 	setMouseTracking (true);
 	setFocusPolicy (Qt::WheelFocus);
-	compileAllObjects();
+	
+	g_vertexCompiler.compileFile();
 }
 
 // =============================================================================
@@ -261,107 +259,15 @@
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-void GLRenderer::setObjectColor (LDObject* obj, const ListType list)
-{	QColor qcol;
-
-	if (!obj->isColored())
-		return;
-
-	if (list == GL::PickList)
-	{	// Make the color by the object's ID if we're picking, so we can make the
-		// ID again from the color we get from the picking results. Be sure to use
-		// the top level parent's index since we want a subfile's children point
-		// to the subfile itself.
-		long i = obj->topLevelParent()->id();
-
-		// Calculate a color based from this index. This method caters for
-		// 16777216 objects. I don't think that'll be exceeded anytime soon. :)
-		// ATM biggest is 53588.dat with 12600 lines.
-		double r = (i / (256 * 256)) % 256,
-			   g = (i / 256) % 256,
-			   b = i % 256;
-
-		qglColor (QColor (r, g, b));
-		return;
-	}
-
-	if ( (list == BFCFrontList || list == BFCBackList) &&
-			obj->getType() != LDObject::Line &&
-			obj->getType() != LDObject::CndLine)
-	{
-
-		if (list == GL::BFCFrontList)
-			qcol = QColor (40, 192, 0);
-		else
-			qcol = QColor (224, 0, 0);
-	}
-	else
-	{	if (obj->color() == maincolor)
-			qcol = getMainColor();
-		else
-		{	LDColor* col = getColor (obj->color());
-
-			if (col)
-				qcol = col->faceColor;
-		}
-
-		if (obj->color() == edgecolor)
-		{	qcol = luma (m_bgcolor) < 40 ? QColor (64, 64, 64) : Qt::black;
-			LDColor* col;
-
-			if (!gl_blackedges && obj->parent() && (col = getColor (obj->parent()->color())))
-				qcol = col->edgeColor;
-		}
-
-		if (qcol.isValid() == false)
-		{	// The color was unknown. Use main color to make the object at least
-			// not appear pitch-black.
-			if (obj->color() != edgecolor)
-				qcol = getMainColor();
-
-			// Warn about the unknown colors, but only once.
-			for (short i : g_warnedColors)
-				if (obj->color() == i)
-					return;
-
-			log ("%1: Unknown color %2!\n", __func__, obj->color());
-			g_warnedColors << obj->color();
-			return;
-		}
-	}
-
-	long r = qcol.red(),
-		 g = qcol.green(),
-		 b = qcol.blue(),
-		 a = qcol.alpha();
-
-	if (obj->topLevelParent()->selected())
-	{	// Brighten it up for the select list.
-		const uchar add = 51;
-
-		r = min (r + add, 255l);
-		g = min (g + add, 255l);
-		b = min (b + add, 255l);
-	}
-
-	glColor4f (
-		((double) r) / 255.0f,
-		((double) g) / 255.0f,
-		((double) b) / 255.0f,
-		((double) a) / 255.0f);
-}
-
-// =============================================================================
-// -----------------------------------------------------------------------------
-void GLRenderer::refresh()
-{	update();
+void GLRenderer::refresh() {
+	update();
 	swapBuffers();
 }
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-void GLRenderer::hardRefresh()
-{	compileAllObjects();
+void GLRenderer::hardRefresh() {
+	g_vertexCompiler.compileFile();
 	refresh();
 
 	glLineWidth (gl_linethickness);
@@ -409,7 +315,7 @@
 		}
 
 		// Back camera needs to be handled differently
-		if (m_camera == GLRenderer::Back)
+		if (m_camera == GL::Back)
 		{	glRotatef (180.0f, 1.0f, 0.0f, 0.0f);
 			glRotatef (180.0f, 0.0f, 0.0f, 1.0f);
 		}
@@ -425,36 +331,29 @@
 		glRotatef (rot (Y), 0.0f, 1.0f, 0.0f);
 		glRotatef (rot (Z), 0.0f, 0.0f, 1.0f);
 	}
-
-	const GL::ListType list = (!drawOnly() && m_picking) ? PickList : NormalList;
-
-	if (gl_colorbfc && !m_picking && !drawOnly())
-	{	glEnable (GL_CULL_FACE);
+	
+	// Draw the VAOs now
+	glEnableClientState (GL_VERTEX_ARRAY);
+	glEnableClientState (GL_COLOR_ARRAY);
+	glDisableClientState (GL_NORMAL_ARRAY);
 
-		for (LDObject* obj : file()->objects())
-		{	if (obj->hidden())
-				continue;
-
-			glCullFace (GL_BACK);
-			glCallList (obj->glLists[BFCFrontList]);
+	if (gl_colorbfc) {
+		glEnable (GL_CULL_FACE);
+		glCullFace (GL_CCW);
+	} else
+		glDisable (GL_CULL_FACE);
 
-			glCullFace (GL_FRONT);
-			glCallList (obj->glLists[BFCBackList]);
-		}
+	drawVAOs ((m_picking ? PickArray : gl_colorbfc ? BFCArray : MainArray), GL_TRIANGLES);
+	drawVAOs ((m_picking ? EdgePickArray : EdgeArray), GL_LINES);
 
-		glDisable (GL_CULL_FACE);
+	// Draw conditional lines. Note that conditional lines are drawn into
+	// EdgePickArray in the picking scene, so when picking, don't do anything
+	// here.
+	if (!m_picking) {
+		glEnable (GL_LINE_STIPPLE);
+		drawVAOs (CondEdgeArray, GL_LINES);
+		glDisable (GL_LINE_STIPPLE);
 	}
-	else
-	{	for (LDObject* obj : file()->objects())
-		{	if (obj->hidden())
-				continue;
-
-			glCallList (obj->glLists[list]);
-		}
-	}
-
-	if (gl_axes && !m_picking && !drawOnly())
-		glCallList (m_axeslist);
 
 	glPopMatrix();
 	glMatrixMode (GL_MODELVIEW);
@@ -463,6 +362,14 @@
 
 // =============================================================================
 // -----------------------------------------------------------------------------
+void GLRenderer::drawVAOs (VAOType arrayType, GLenum type) {
+	const VertexCompiler::Array* array = g_vertexCompiler.getMergedBuffer (arrayType);
+	glVertexPointer (3, GL_FLOAT, sizeof (VertexCompiler::Vertex), &array->data()[0].x);
+	glColorPointer (4, GL_UNSIGNED_BYTE, sizeof (VertexCompiler::Vertex), &array->data()[0].color);
+	glDrawArrays (type, 0, array->writtenSize() / sizeof (VertexCompiler::Vertex));
+}
+
+// =============================================================================
 // 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.
 // -----------------------------------------------------------------------------
@@ -800,127 +707,8 @@
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-QColor GLRenderer::getTextPen () const
-{	return m_darkbg ? Qt::white : Qt::black;
-}
-
-// =============================================================================
-// -----------------------------------------------------------------------------
 void GLRenderer::compileAllObjects()
-{	if (!file())
-		return;
-
-	// Compiling all is a big job, use a busy cursor
-	setCursor (Qt::BusyCursor);
-
-	m_knownVerts.clear();
-
-	for (LDObject* obj : file()->objects())
-		compileObject (obj);
-
-	// Compile axes
-	glDeleteLists (m_axeslist, 1);
-	m_axeslist = glGenLists (1);
-	glNewList (m_axeslist, GL_COMPILE);
-	glBegin (GL_LINES);
-
-	for (const LDGLAxis& ax : g_GLAxes)
-	{	qglColor (ax.col);
-		compileVertex (ax.vert);
-		compileVertex (-ax.vert);
-	}
-
-	glEnd();
-	glEndList();
-
-	setCursor (Qt::ArrowCursor);
-}
-
-// =============================================================================
-// -----------------------------------------------------------------------------
-void GLRenderer::compileSubObject (LDObject* obj, const GLenum gltype)
-{	glBegin (gltype);
-
-	const int numverts = (obj->getType() != LDObject::CndLine) ? obj->vertices() : 2;
-
-	if (g_glInvert == false)
-		for (int i = 0; i < numverts; ++i)
-			compileVertex (obj->getVertex (i));
-	else
-		for (int i = numverts - 1; i >= 0; --i)
-			compileVertex (obj->getVertex (i));
-
-	glEnd();
-}
-
-// =============================================================================
-// -----------------------------------------------------------------------------
-void GLRenderer::compileList (LDObject* obj, const GLRenderer::ListType list)
-{	setObjectColor (obj, list);
-
-	switch (obj->getType())
-	{	case LDObject::Line:
-			compileSubObject (obj, GL_LINES);
-			break;
-
-		case LDObject::CndLine:
-
-			// Draw conditional lines with a dash pattern - however, use a full
-			// line when drawing a pick list to make selecting them easier.
-			if (list != GL::PickList)
-			{	glLineStipple (1, 0x6666);
-				glEnable (GL_LINE_STIPPLE);
-			}
-
-			compileSubObject (obj, GL_LINES);
-
-			glDisable (GL_LINE_STIPPLE);
-			break;
-
-		case LDObject::Triangle:
-			compileSubObject (obj, GL_TRIANGLES);
-			break;
-
-		case LDObject::Quad:
-			compileSubObject (obj, GL_QUADS);
-			break;
-
-		case LDObject::Subfile:
-		{	LDSubfile* ref = static_cast<LDSubfile*> (obj);
-			QList<LDObject*> objs;
-
-			objs = ref->inlineContents (
-					   LDSubfile::DeepInline |
-					   LDSubfile::CacheInline |
-					   LDSubfile::RendererInline);
-			bool oldinvert = g_glInvert;
-
-			if (ref->transform().determinant() < 0)
-				g_glInvert = !g_glInvert;
-
-			LDObject* prev = ref->prev();
-
-			if (prev && prev->getType() == LDObject::BFC && static_cast<LDBFC*> (prev)->type == LDBFC::InvertNext)
-				g_glInvert = !g_glInvert;
-
-		for (LDObject * obj : objs)
-			{	compileList (obj, list);
-				delete obj;
-			}
-
-			g_glInvert = oldinvert;
-		}
-		break;
-
-		default:
-			break;
-	}
-}
-
-// =============================================================================
-// -----------------------------------------------------------------------------
-void GLRenderer::compileVertex (const vertex& vrt)
-{	glVertex3d (vrt[X], -vrt[Y], -vrt[Z]);
+{	g_vertexCompiler.compileFile();
 }
 
 // =============================================================================
@@ -1346,8 +1134,9 @@
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-SET_ACCESSOR (LDFile*, GLRenderer::setFile)
-{	m_file = val;
+SET_ACCESSOR (LDFile*, GLRenderer::setFile) {
+	m_file = val;
+	g_vertexCompiler.setFile (val);
 
 	if (val != null)
 		overlaysFromObjects();
@@ -1581,27 +1370,8 @@
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-void GLRenderer::compileObject (LDObject* obj)
-{	deleteLists (obj);
-
-for (const GL::ListType listType : g_glListTypes)
-	{	if (drawOnly() && listType != GL::NormalList)
-			continue;
-
-		GLuint list = glGenLists (1);
-		glNewList (list, GL_COMPILE);
-
-		obj->glLists[listType] = list;
-		compileList (obj, listType);
-
-		glEndList();
-	}
-
-	// Mark in known vertices of this object
-	QList<vertex> verts = getVertices (obj);
-	m_knownVerts << verts;
-	removeDuplicates (m_knownVerts);
-
+void GLRenderer::compileObject (LDObject* obj) {
+	g_vertexCompiler.stageForCompilation (obj);
 	obj->m_glinit = true;
 }
 
--- a/src/gldraw.h	Tue Oct 22 22:14:32 2013 +0300
+++ b/src/gldraw.h	Wed Oct 23 12:46:10 2013 +0300
@@ -201,6 +201,9 @@
 		// Convert a 3D point to a 2D point
 		QPoint         coordconv3_2 (const vertex& pos3d) const;
 
+		// Draw a VAO array
+		void           drawVAOs (VAOType arrayType, GLenum type);
+
 		// Determine which color to draw text with
 		QColor         getTextPen() const;
 
--- a/src/ldtypes.cpp	Tue Oct 22 22:14:32 2013 +0300
+++ b/src/ldtypes.cpp	Wed Oct 23 12:46:10 2013 +0300
@@ -24,6 +24,7 @@
 #include "history.h"
 #include "gldraw.h"
 #include "colors.h"
+#include "gldata.h"
 
 cfg (String, ld_defaultname, "");
 cfg (String, ld_defaultuser, "");

mercurial