Renamed glCompiler.cpp → glcompiler.cpp

Tue, 14 Feb 2017 14:53:06 +0200

author
Teemu Piippo <teemu@hecknology.net>
date
Tue, 14 Feb 2017 14:53:06 +0200
changeset 1146
bb728c124d47
parent 1145
02264bf0108d
child 1147
a26568aa3cce

Renamed glCompiler.cpp → glcompiler.cpp

CMakeLists.txt file | annotate | diff | comparison | revisions
src/glCompiler.cpp file | annotate | diff | comparison | revisions
src/glCompiler.h file | annotate | diff | comparison | revisions
src/glcompiler.cpp file | annotate | diff | comparison | revisions
src/glcompiler.h file | annotate | diff | comparison | revisions
src/glrenderer.cpp file | annotate | diff | comparison | revisions
src/ldObject.cpp file | annotate | diff | comparison | revisions
src/mainwindow.cpp file | annotate | diff | comparison | revisions
src/toolsets/viewtoolset.cpp file | annotate | diff | comparison | revisions
--- a/CMakeLists.txt	Tue Feb 14 14:52:01 2017 +0200
+++ b/CMakeLists.txt	Tue Feb 14 14:53:06 2017 +0200
@@ -36,7 +36,7 @@
 	src/documentmanager.cpp
 	src/editHistory.cpp
 	src/glcamera.cpp
-	src/glCompiler.cpp
+	src/glcompiler.cpp
 	src/glrenderer.cpp
 	src/grid.cpp
 	src/guiutilities.cpp
@@ -98,7 +98,7 @@
 	src/editHistory.h
 	src/format.h
 	src/glcamera.h
-	src/glCompiler.h
+	src/glcompiler.h
 	src/glrenderer.h
 	src/grid.h
 	src/guiutilities.h
--- a/src/glCompiler.cpp	Tue Feb 14 14:52:01 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,432 +0,0 @@
-/*
- *  LDForge: LDraw parts authoring CAD
- *  Copyright (C) 2013 - 2017 Teemu Piippo
- *
- *  This program is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#define GL_GLEXT_PROTOTYPES
-#include <GL/glu.h>
-#include <GL/glext.h>
-#include "glCompiler.h"
-#include "miscallenous.h"
-#include "guiutilities.h"
-#include "documentmanager.h"
-#include "grid.h"
-
-struct GLErrorInfo
-{
-	GLenum	value;
-	QString	text;
-};
-
-static const GLErrorInfo g_GLErrors[] =
-{
-	{ GL_NO_ERROR,						"No error" },
-	{ GL_INVALID_ENUM,					"Unacceptable enumerator passed" },
-	{ GL_INVALID_VALUE,					"Numeric argument out of range" },
-	{ GL_INVALID_OPERATION,				"The operation is not allowed to be done in this state" },
-	{ GL_INVALID_FRAMEBUFFER_OPERATION,	"Framebuffer object is not complete"},
-	{ GL_OUT_OF_MEMORY,					"Out of memory" },
-	{ GL_STACK_UNDERFLOW,				"The operation would have caused an underflow" },
-	{ GL_STACK_OVERFLOW,				"The operation would have caused an overflow" },
-};
-
-void CheckGLErrorImpl (const char* file, int line)
-{
-	QString errmsg;
-	GLenum errnum = glGetError();
-
-	if (errnum == GL_NO_ERROR)
-		return;
-
-	for (const GLErrorInfo& err : g_GLErrors)
-	{
-		if (err.value == errnum)
-		{
-			errmsg = err.text;
-			break;
-		}
-	}
-
-	print ("OpenGL ERROR: at %1:%2: %3", Basename (QString (file)), line, errmsg);
-}
-
-
-GLCompiler::GLCompiler (GLRenderer* renderer) :
-	HierarchyElement (renderer),
-	m_renderer (renderer)
-{
-	connect(renderer->model(), SIGNAL(objectAdded(LDObject*)), this, SLOT(compileObject(LDObject*)));
-	connect(renderer->model(), SIGNAL(objectModified(LDObject*)), this, SLOT(compileObject(LDObject*)));
-	connect(renderer->model(), SIGNAL(aboutToRemoveObject(LDObject*)), this, SLOT(forgetObject(LDObject*)), Qt::DirectConnection);
-	connect(renderer, SIGNAL(objectHighlightingChanged(LDObject*)), this, SLOT(compileObject(LDObject*)));
-	connect(m_window, SIGNAL(gridChanged()), this, SLOT(recompile()));
-
-	for (LDObject* object : renderer->model()->objects())
-		stageForCompilation(object);
-}
-
-
-void GLCompiler::initialize()
-{
-	initializeOpenGLFunctions();
-	glGenBuffers (NumVbos, &m_vbo[0]);
-	CHECK_GL_ERROR();
-}
-
-
-GLCompiler::~GLCompiler()
-{
-	glDeleteBuffers (NumVbos, &m_vbo[0]);
-	CHECK_GL_ERROR();
-}
-
-
-QColor GLCompiler::indexColorForID (int id) const
-{
-	// Calculate a color based from this index. This method caters for
-	// 16777216 objects. I don't think that will be exceeded anytime soon. :)
-	int r = (id / 0x10000) % 0x100;
-	int g = (id / 0x100) % 0x100;
-	int b = id % 0x100;
-	return {r, g, b};
-}
-
-/*
- * Returns the suitable color for the polygon.
- * - polygon is the polygon to colorise.
- * - polygonOwner is the LDObject from which the polygon originated.
- * - subclass provides context for the polygon.
- */
-QColor GLCompiler::getColorForPolygon(LDPolygon& polygon, LDObject* polygonOwner, VboSubclass subclass) const
-{
-	QColor color;
-
-	switch (subclass)
-	{
-	case VboSubclass::Surfaces:
-	case VboSubclass::Normals:
-	case VboSubclass::_End:
-		// Surface and normal VBOs contain vertex data, not colors. So we can't return anything meaningful.
-		return {};
-
-	case VboSubclass::BfcFrontColors:
-		// Use the constant green color for BFC front colors
-		return {64, 192, 80};
-
-	case VboSubclass::BfcBackColors:
-		// Use the constant red color for BFC back colors
-		return {208, 64, 64};
-
-	case VboSubclass::PickColors:
-		// For the picking scene, determine the color from the owner's ID.
-		return indexColorForID(polygonOwner->id());
-
-	case VboSubclass::RandomColors:
-		// For the random color scene, the owner object has rolled up a random color. Use that.
-		color = polygonOwner->randomColor();
-		break;
-
-	case VboSubclass::NormalColors:
-		// For normal colors, use the polygon's color.
-		if (polygon.color == MainColor)
-		{
-			// If it's the main color, use the polygon owner's color.
-			if (polygonOwner->color() == MainColor)
-			{
-				// If that also is the main color, then we whatever the user has configured the main color to look like.
-				color = guiUtilities()->mainColorRepresentation();
-			}
-			else
-			{
-				color = polygonOwner->color().faceColor();
-			}
-		}
-		else if (polygon.color == EdgeColor)
-		{
-			// Edge color is black, unless we have a dark background, in which case lines need to be bright.
-			color = luma(m_config->backgroundColor()) > 40 ? Qt::black : Qt::white;
-		}
-		else
-		{
-			// Not main or edge color, use the polygon's color as is.
-			color = LDColor {polygon.color}.faceColor();
-		}
-		break;
-	}
-
-	if (color.isValid())
-	{
-		// We may wish to apply blending on the color to indicate selection or highlight.
-		double blendAlpha = 0.0;
-
-		if (polygonOwner->isSelected())
-			blendAlpha = 1.0;
-		else if (polygonOwner == m_renderer->objectAtCursor())
-			blendAlpha = 0.5;
-
-		if (blendAlpha != 0.0)
-		{
-			QColor selectedColor = m_config->selectColorBlend();
-			double denominator = blendAlpha + 1.0;
-			color.setRed((color.red() + (selectedColor.red() * blendAlpha)) / denominator);
-			color.setGreen((color.green() + (selectedColor.green() * blendAlpha)) / denominator);
-			color.setBlue((color.blue() + (selectedColor.blue() * blendAlpha)) / denominator);
-		}
-	}
-	else
-	{
-		// The color was unknown. Use main color to make the polygon at least not appear pitch-black.
-		if (polygon.num != 2 and polygon.num != 5)
-			color = guiUtilities()->mainColorRepresentation();
-		else
-			color = Qt::black;
-
-		// Warn about the unknown color, but only once.
-		static QSet<int> warnedColors;
-		if (not warnedColors.contains(polygon.color))
-		{
-			print("Unknown color %1!\n", polygon.color);
-			warnedColors.insert(polygon.color);
-		}
-	}
-
-	return color;
-}
-
-
-void GLCompiler::needMerge()
-{
-	for (int i = 0; i < countof (m_vboChanged); ++i)
-		m_vboChanged[i] = true;
-}
-
-
-void GLCompiler::stageForCompilation (LDObject* obj)
-{
-	m_staged << obj;
-}
-
-
-void GLCompiler::unstage (LDObject* obj)
-{
-	m_staged.remove (obj);
-}
-
-
-void GLCompiler::compileStaged()
-{
-	for (LDObject* object : m_staged)
-		compileObject(object);
-
-	m_staged.clear();
-}
-
-
-void GLCompiler::prepareVBO (int vbonum, const Model* model)
-{
-	// Compile anything that still awaits it
-	compileStaged();
-
-	if (not m_vboChanged[vbonum])
-		return;
-
-	QVector<GLfloat> vbodata;
-
-	for (auto it = m_objectInfo.begin(); it != m_objectInfo.end();)
-	{
-		if (it.key() == nullptr)
-		{
-			it = m_objectInfo.erase (it);
-			continue;
-		}
-
-		if (it.key()->model() == model and not it.key()->isHidden())
-			vbodata += it->data[vbonum];
-
-		++it;
-	}
-
-	glBindBuffer (GL_ARRAY_BUFFER, m_vbo[vbonum]);
-	glBufferData (GL_ARRAY_BUFFER, countof(vbodata) * sizeof(GLfloat), vbodata.constData(), GL_STATIC_DRAW);
-	glBindBuffer (GL_ARRAY_BUFFER, 0);
-	CHECK_GL_ERROR();
-	m_vboChanged[vbonum] = false;
-	m_vboSizes[vbonum] = countof(vbodata);
-}
-
-
-void GLCompiler::dropObjectInfo(LDObject* object)
-{
-	if (m_objectInfo.contains(object))
-	{
-		m_objectInfo.remove(object);
-		needMerge();
-	}
-}
-
-void GLCompiler::forgetObject(LDObject* object)
-{
-	dropObjectInfo(object);
-	m_staged.remove(object);
-}
-
-
-void GLCompiler::compileObject (LDObject* obj)
-{
-	if (obj == nullptr)
-		return;
-
-	ObjectVBOInfo info;
-	info.isChanged = true;
-	dropObjectInfo (obj);
-
-	switch (obj->type())
-	{
-	// Note: We cannot split quads into triangles here, it would mess up the wireframe view.
-	// Quads must go into separate vbos.
-	case LDObjectType::Triangle:
-	case LDObjectType::Quadrilateral:
-	case LDObjectType::EdgeLine:
-	case LDObjectType::ConditionalEdge:
-		{
-			LDPolygon* poly = obj->getPolygon();
-			poly->id = obj->id();
-			compilePolygon (*poly, obj, &info);
-			delete poly;
-			break;
-		}
-
-	case LDObjectType::SubfileReference:
-		{
-			LDSubfileReference* ref = static_cast<LDSubfileReference*> (obj);
-			auto data = ref->inlinePolygons();
-
-			for (LDPolygon& poly : data)
-			{
-				poly.id = obj->id();
-				compilePolygon (poly, obj, &info);
-			}
-			break;
-		}
-
-	case LDObjectType::BezierCurve:
-		{
-			LDBezierCurve* curve = static_cast<LDBezierCurve*> (obj);
-			for (LDPolygon& polygon : curve->rasterizePolygons(grid()->bezierCurveSegments()))
-			{
-				polygon.id = obj->id();
-				compilePolygon (polygon, obj, &info);
-			}
-		}
-		break;
-
-	default:
-		break;
-	}
-
-	m_objectInfo[obj] = info;
-	needMerge();
-}
-
-
-void GLCompiler::compilePolygon (LDPolygon& poly, LDObject* topobj, ObjectVBOInfo* objinfo)
-{
-	VboClass surface;
-	int vertexCount;
-
-	switch (poly.num)
-	{
-	case 2:	surface = VboClass::Lines;				vertexCount = 2; break;
-	case 3:	surface = VboClass::Triangles;			vertexCount = 3; break;
-	case 4:	surface = VboClass::Quads;				vertexCount = 4; break;
-	case 5:	surface = VboClass::ConditionalLines;	vertexCount = 2; break;
-	default: return;
-	}
-
-	// Determine the normals for the polygon.
-	Vertex normals[4];
-	auto vertexRing = ring(poly.vertices, vertexCount);
-
-	for (int i = 0; i < vertexCount; ++i)
-	{
-		const Vertex& v1 = vertexRing[i - 1];
-		const Vertex& v2 = vertexRing[i];
-		const Vertex& v3 = vertexRing[i + 1];
-		normals[i] = Vertex::crossProduct(v3 - v2, v1 - v2).normalized();
-	}
-
-	for (VboSubclass complement : iterateEnum<VboSubclass>())
-	{
-		const int vbonum = vboNumber (surface, complement);
-		QVector<GLfloat>& vbodata = objinfo->data[vbonum];
-		const QColor color = getColorForPolygon (poly, topobj, complement);
-
-		for (int vert = 0; vert < vertexCount; ++vert)
-		{
-			if (complement == VboSubclass::Surfaces)
-			{
-				// Write coordinates. Apparently Z must be flipped too?
-				vbodata	<< poly.vertices[vert].x()
-						<< -poly.vertices[vert].y()
-						<< -poly.vertices[vert].z();
-			}
-			else if (complement == VboSubclass::Normals)
-			{
-				vbodata << normals[vert].x()
-				        << -normals[vert].y()
-				        << -normals[vert].z();
-			}
-			else
-			{
-				vbodata	<< ((GLfloat) color.red()) / 255.0f
-						<< ((GLfloat) color.green()) / 255.0f
-						<< ((GLfloat) color.blue()) / 255.0f
-						<< ((GLfloat) color.alpha()) / 255.0f;
-			}
-		}
-	}
-}
-
-
-void GLCompiler::setRenderer (GLRenderer* renderer)
-{
-	m_renderer = renderer;
-}
-
-
-int GLCompiler::vboNumber (VboClass surface, VboSubclass complement)
-{
-	return (static_cast<int>(surface) * EnumLimits<VboSubclass>::Count) + static_cast<int>(complement);
-}
-
-
-GLuint GLCompiler::vbo (int vbonum) const
-{
-	return m_vbo[vbonum];
-}
-
-
-int GLCompiler::vboSize (int vbonum) const
-{
-	return m_vboSizes[vbonum];
-}
-
-
-void GLCompiler::recompile()
-{
-	for (LDObject* object : m_renderer->model()->objects())
-		compileObject(object);
-}
--- a/src/glCompiler.h	Tue Feb 14 14:52:01 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/*
- *  LDForge: LDraw parts authoring CAD
- *  Copyright (C) 2013 - 2017 Teemu Piippo
- *
- *  This program is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#pragma once
-#include "main.h"
-#include "glrenderer.h"
-#include "glShared.h"
-#include <QMap>
-#include <QSet>
-
-// =============================================================================
-//
-class GLCompiler : public QObject, public HierarchyElement, protected QOpenGLFunctions
-{
-	Q_OBJECT
-
-public:
-	struct ObjectVBOInfo
-	{
-		QVector<GLfloat>	data[NumVbos];
-		bool				isChanged;
-	};
-
-	GLCompiler (GLRenderer* renderer);
-	~GLCompiler();
-	QColor getColorForPolygon (LDPolygon& poly, LDObject* topobj, VboSubclass complement) const;
-	QColor indexColorForID (int id) const;
-	void initialize();
-	void needMerge();
-	void prepareVBO (int vbonum, const Model* model);
-	void setRenderer (GLRenderer* compiler);
-	void stageForCompilation (LDObject* obj);
-	void unstage (LDObject* obj);
-	GLuint vbo (int vbonum) const;
-	int vboSize (int vbonum) const;
-
-	static int vboNumber (VboClass surface, VboSubclass complement);
-
-private:
-	void compileStaged();
-	void compilePolygon (LDPolygon& poly, LDObject* topobj, ObjectVBOInfo* objinfo);
-	Q_SLOT void compileObject (LDObject* obj);
-	Q_SLOT void recompile();
-	void dropObjectInfo (LDObject* obj);
-	Q_SLOT void forgetObject(LDObject* object);
-
-private:
-	QMap<LDObject*, ObjectVBOInfo>	m_objectInfo;
-	QSet<LDObject*> m_staged; // Objects that need to be compiled
-	GLuint m_vbo[NumVbos];
-	bool m_vboChanged[NumVbos] = {true};
-	int m_vboSizes[NumVbos] = {0};
-	GLRenderer* m_renderer;
-};
-
-#define CHECK_GL_ERROR() { CheckGLErrorImpl (__FILE__, __LINE__); }
-void CheckGLErrorImpl (const char* file, int line);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/glcompiler.cpp	Tue Feb 14 14:53:06 2017 +0200
@@ -0,0 +1,432 @@
+/*
+ *  LDForge: LDraw parts authoring CAD
+ *  Copyright (C) 2013 - 2017 Teemu Piippo
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glu.h>
+#include <GL/glext.h>
+#include "glcompiler.h"
+#include "miscallenous.h"
+#include "guiutilities.h"
+#include "documentmanager.h"
+#include "grid.h"
+
+struct GLErrorInfo
+{
+	GLenum	value;
+	QString	text;
+};
+
+static const GLErrorInfo g_GLErrors[] =
+{
+	{ GL_NO_ERROR,						"No error" },
+	{ GL_INVALID_ENUM,					"Unacceptable enumerator passed" },
+	{ GL_INVALID_VALUE,					"Numeric argument out of range" },
+	{ GL_INVALID_OPERATION,				"The operation is not allowed to be done in this state" },
+	{ GL_INVALID_FRAMEBUFFER_OPERATION,	"Framebuffer object is not complete"},
+	{ GL_OUT_OF_MEMORY,					"Out of memory" },
+	{ GL_STACK_UNDERFLOW,				"The operation would have caused an underflow" },
+	{ GL_STACK_OVERFLOW,				"The operation would have caused an overflow" },
+};
+
+void CheckGLErrorImpl (const char* file, int line)
+{
+	QString errmsg;
+	GLenum errnum = glGetError();
+
+	if (errnum == GL_NO_ERROR)
+		return;
+
+	for (const GLErrorInfo& err : g_GLErrors)
+	{
+		if (err.value == errnum)
+		{
+			errmsg = err.text;
+			break;
+		}
+	}
+
+	print ("OpenGL ERROR: at %1:%2: %3", Basename (QString (file)), line, errmsg);
+}
+
+
+GLCompiler::GLCompiler (GLRenderer* renderer) :
+	HierarchyElement (renderer),
+	m_renderer (renderer)
+{
+	connect(renderer->model(), SIGNAL(objectAdded(LDObject*)), this, SLOT(compileObject(LDObject*)));
+	connect(renderer->model(), SIGNAL(objectModified(LDObject*)), this, SLOT(compileObject(LDObject*)));
+	connect(renderer->model(), SIGNAL(aboutToRemoveObject(LDObject*)), this, SLOT(forgetObject(LDObject*)), Qt::DirectConnection);
+	connect(renderer, SIGNAL(objectHighlightingChanged(LDObject*)), this, SLOT(compileObject(LDObject*)));
+	connect(m_window, SIGNAL(gridChanged()), this, SLOT(recompile()));
+
+	for (LDObject* object : renderer->model()->objects())
+		stageForCompilation(object);
+}
+
+
+void GLCompiler::initialize()
+{
+	initializeOpenGLFunctions();
+	glGenBuffers (NumVbos, &m_vbo[0]);
+	CHECK_GL_ERROR();
+}
+
+
+GLCompiler::~GLCompiler()
+{
+	glDeleteBuffers (NumVbos, &m_vbo[0]);
+	CHECK_GL_ERROR();
+}
+
+
+QColor GLCompiler::indexColorForID (int id) const
+{
+	// Calculate a color based from this index. This method caters for
+	// 16777216 objects. I don't think that will be exceeded anytime soon. :)
+	int r = (id / 0x10000) % 0x100;
+	int g = (id / 0x100) % 0x100;
+	int b = id % 0x100;
+	return {r, g, b};
+}
+
+/*
+ * Returns the suitable color for the polygon.
+ * - polygon is the polygon to colorise.
+ * - polygonOwner is the LDObject from which the polygon originated.
+ * - subclass provides context for the polygon.
+ */
+QColor GLCompiler::getColorForPolygon(LDPolygon& polygon, LDObject* polygonOwner, VboSubclass subclass) const
+{
+	QColor color;
+
+	switch (subclass)
+	{
+	case VboSubclass::Surfaces:
+	case VboSubclass::Normals:
+	case VboSubclass::_End:
+		// Surface and normal VBOs contain vertex data, not colors. So we can't return anything meaningful.
+		return {};
+
+	case VboSubclass::BfcFrontColors:
+		// Use the constant green color for BFC front colors
+		return {64, 192, 80};
+
+	case VboSubclass::BfcBackColors:
+		// Use the constant red color for BFC back colors
+		return {208, 64, 64};
+
+	case VboSubclass::PickColors:
+		// For the picking scene, determine the color from the owner's ID.
+		return indexColorForID(polygonOwner->id());
+
+	case VboSubclass::RandomColors:
+		// For the random color scene, the owner object has rolled up a random color. Use that.
+		color = polygonOwner->randomColor();
+		break;
+
+	case VboSubclass::NormalColors:
+		// For normal colors, use the polygon's color.
+		if (polygon.color == MainColor)
+		{
+			// If it's the main color, use the polygon owner's color.
+			if (polygonOwner->color() == MainColor)
+			{
+				// If that also is the main color, then we whatever the user has configured the main color to look like.
+				color = guiUtilities()->mainColorRepresentation();
+			}
+			else
+			{
+				color = polygonOwner->color().faceColor();
+			}
+		}
+		else if (polygon.color == EdgeColor)
+		{
+			// Edge color is black, unless we have a dark background, in which case lines need to be bright.
+			color = luma(m_config->backgroundColor()) > 40 ? Qt::black : Qt::white;
+		}
+		else
+		{
+			// Not main or edge color, use the polygon's color as is.
+			color = LDColor {polygon.color}.faceColor();
+		}
+		break;
+	}
+
+	if (color.isValid())
+	{
+		// We may wish to apply blending on the color to indicate selection or highlight.
+		double blendAlpha = 0.0;
+
+		if (polygonOwner->isSelected())
+			blendAlpha = 1.0;
+		else if (polygonOwner == m_renderer->objectAtCursor())
+			blendAlpha = 0.5;
+
+		if (blendAlpha != 0.0)
+		{
+			QColor selectedColor = m_config->selectColorBlend();
+			double denominator = blendAlpha + 1.0;
+			color.setRed((color.red() + (selectedColor.red() * blendAlpha)) / denominator);
+			color.setGreen((color.green() + (selectedColor.green() * blendAlpha)) / denominator);
+			color.setBlue((color.blue() + (selectedColor.blue() * blendAlpha)) / denominator);
+		}
+	}
+	else
+	{
+		// The color was unknown. Use main color to make the polygon at least not appear pitch-black.
+		if (polygon.num != 2 and polygon.num != 5)
+			color = guiUtilities()->mainColorRepresentation();
+		else
+			color = Qt::black;
+
+		// Warn about the unknown color, but only once.
+		static QSet<int> warnedColors;
+		if (not warnedColors.contains(polygon.color))
+		{
+			print("Unknown color %1!\n", polygon.color);
+			warnedColors.insert(polygon.color);
+		}
+	}
+
+	return color;
+}
+
+
+void GLCompiler::needMerge()
+{
+	for (int i = 0; i < countof (m_vboChanged); ++i)
+		m_vboChanged[i] = true;
+}
+
+
+void GLCompiler::stageForCompilation (LDObject* obj)
+{
+	m_staged << obj;
+}
+
+
+void GLCompiler::unstage (LDObject* obj)
+{
+	m_staged.remove (obj);
+}
+
+
+void GLCompiler::compileStaged()
+{
+	for (LDObject* object : m_staged)
+		compileObject(object);
+
+	m_staged.clear();
+}
+
+
+void GLCompiler::prepareVBO (int vbonum, const Model* model)
+{
+	// Compile anything that still awaits it
+	compileStaged();
+
+	if (not m_vboChanged[vbonum])
+		return;
+
+	QVector<GLfloat> vbodata;
+
+	for (auto it = m_objectInfo.begin(); it != m_objectInfo.end();)
+	{
+		if (it.key() == nullptr)
+		{
+			it = m_objectInfo.erase (it);
+			continue;
+		}
+
+		if (it.key()->model() == model and not it.key()->isHidden())
+			vbodata += it->data[vbonum];
+
+		++it;
+	}
+
+	glBindBuffer (GL_ARRAY_BUFFER, m_vbo[vbonum]);
+	glBufferData (GL_ARRAY_BUFFER, countof(vbodata) * sizeof(GLfloat), vbodata.constData(), GL_STATIC_DRAW);
+	glBindBuffer (GL_ARRAY_BUFFER, 0);
+	CHECK_GL_ERROR();
+	m_vboChanged[vbonum] = false;
+	m_vboSizes[vbonum] = countof(vbodata);
+}
+
+
+void GLCompiler::dropObjectInfo(LDObject* object)
+{
+	if (m_objectInfo.contains(object))
+	{
+		m_objectInfo.remove(object);
+		needMerge();
+	}
+}
+
+void GLCompiler::forgetObject(LDObject* object)
+{
+	dropObjectInfo(object);
+	m_staged.remove(object);
+}
+
+
+void GLCompiler::compileObject (LDObject* obj)
+{
+	if (obj == nullptr)
+		return;
+
+	ObjectVBOInfo info;
+	info.isChanged = true;
+	dropObjectInfo (obj);
+
+	switch (obj->type())
+	{
+	// Note: We cannot split quads into triangles here, it would mess up the wireframe view.
+	// Quads must go into separate vbos.
+	case LDObjectType::Triangle:
+	case LDObjectType::Quadrilateral:
+	case LDObjectType::EdgeLine:
+	case LDObjectType::ConditionalEdge:
+		{
+			LDPolygon* poly = obj->getPolygon();
+			poly->id = obj->id();
+			compilePolygon (*poly, obj, &info);
+			delete poly;
+			break;
+		}
+
+	case LDObjectType::SubfileReference:
+		{
+			LDSubfileReference* ref = static_cast<LDSubfileReference*> (obj);
+			auto data = ref->inlinePolygons();
+
+			for (LDPolygon& poly : data)
+			{
+				poly.id = obj->id();
+				compilePolygon (poly, obj, &info);
+			}
+			break;
+		}
+
+	case LDObjectType::BezierCurve:
+		{
+			LDBezierCurve* curve = static_cast<LDBezierCurve*> (obj);
+			for (LDPolygon& polygon : curve->rasterizePolygons(grid()->bezierCurveSegments()))
+			{
+				polygon.id = obj->id();
+				compilePolygon (polygon, obj, &info);
+			}
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	m_objectInfo[obj] = info;
+	needMerge();
+}
+
+
+void GLCompiler::compilePolygon (LDPolygon& poly, LDObject* topobj, ObjectVBOInfo* objinfo)
+{
+	VboClass surface;
+	int vertexCount;
+
+	switch (poly.num)
+	{
+	case 2:	surface = VboClass::Lines;				vertexCount = 2; break;
+	case 3:	surface = VboClass::Triangles;			vertexCount = 3; break;
+	case 4:	surface = VboClass::Quads;				vertexCount = 4; break;
+	case 5:	surface = VboClass::ConditionalLines;	vertexCount = 2; break;
+	default: return;
+	}
+
+	// Determine the normals for the polygon.
+	Vertex normals[4];
+	auto vertexRing = ring(poly.vertices, vertexCount);
+
+	for (int i = 0; i < vertexCount; ++i)
+	{
+		const Vertex& v1 = vertexRing[i - 1];
+		const Vertex& v2 = vertexRing[i];
+		const Vertex& v3 = vertexRing[i + 1];
+		normals[i] = Vertex::crossProduct(v3 - v2, v1 - v2).normalized();
+	}
+
+	for (VboSubclass complement : iterateEnum<VboSubclass>())
+	{
+		const int vbonum = vboNumber (surface, complement);
+		QVector<GLfloat>& vbodata = objinfo->data[vbonum];
+		const QColor color = getColorForPolygon (poly, topobj, complement);
+
+		for (int vert = 0; vert < vertexCount; ++vert)
+		{
+			if (complement == VboSubclass::Surfaces)
+			{
+				// Write coordinates. Apparently Z must be flipped too?
+				vbodata	<< poly.vertices[vert].x()
+						<< -poly.vertices[vert].y()
+						<< -poly.vertices[vert].z();
+			}
+			else if (complement == VboSubclass::Normals)
+			{
+				vbodata << normals[vert].x()
+				        << -normals[vert].y()
+				        << -normals[vert].z();
+			}
+			else
+			{
+				vbodata	<< ((GLfloat) color.red()) / 255.0f
+						<< ((GLfloat) color.green()) / 255.0f
+						<< ((GLfloat) color.blue()) / 255.0f
+						<< ((GLfloat) color.alpha()) / 255.0f;
+			}
+		}
+	}
+}
+
+
+void GLCompiler::setRenderer (GLRenderer* renderer)
+{
+	m_renderer = renderer;
+}
+
+
+int GLCompiler::vboNumber (VboClass surface, VboSubclass complement)
+{
+	return (static_cast<int>(surface) * EnumLimits<VboSubclass>::Count) + static_cast<int>(complement);
+}
+
+
+GLuint GLCompiler::vbo (int vbonum) const
+{
+	return m_vbo[vbonum];
+}
+
+
+int GLCompiler::vboSize (int vbonum) const
+{
+	return m_vboSizes[vbonum];
+}
+
+
+void GLCompiler::recompile()
+{
+	for (LDObject* object : m_renderer->model()->objects())
+		compileObject(object);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/glcompiler.h	Tue Feb 14 14:53:06 2017 +0200
@@ -0,0 +1,72 @@
+/*
+ *  LDForge: LDraw parts authoring CAD
+ *  Copyright (C) 2013 - 2017 Teemu Piippo
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+#include "main.h"
+#include "glrenderer.h"
+#include "glShared.h"
+#include <QMap>
+#include <QSet>
+
+// =============================================================================
+//
+class GLCompiler : public QObject, public HierarchyElement, protected QOpenGLFunctions
+{
+	Q_OBJECT
+
+public:
+	struct ObjectVBOInfo
+	{
+		QVector<GLfloat>	data[NumVbos];
+		bool				isChanged;
+	};
+
+	GLCompiler (GLRenderer* renderer);
+	~GLCompiler();
+	QColor getColorForPolygon (LDPolygon& poly, LDObject* topobj, VboSubclass complement) const;
+	QColor indexColorForID (int id) const;
+	void initialize();
+	void needMerge();
+	void prepareVBO (int vbonum, const Model* model);
+	void setRenderer (GLRenderer* compiler);
+	void stageForCompilation (LDObject* obj);
+	void unstage (LDObject* obj);
+	GLuint vbo (int vbonum) const;
+	int vboSize (int vbonum) const;
+
+	static int vboNumber (VboClass surface, VboSubclass complement);
+
+private:
+	void compileStaged();
+	void compilePolygon (LDPolygon& poly, LDObject* topobj, ObjectVBOInfo* objinfo);
+	Q_SLOT void compileObject (LDObject* obj);
+	Q_SLOT void recompile();
+	void dropObjectInfo (LDObject* obj);
+	Q_SLOT void forgetObject(LDObject* object);
+
+private:
+	QMap<LDObject*, ObjectVBOInfo>	m_objectInfo;
+	QSet<LDObject*> m_staged; // Objects that need to be compiled
+	GLuint m_vbo[NumVbos];
+	bool m_vboChanged[NumVbos] = {true};
+	int m_vboSizes[NumVbos] = {0};
+	GLRenderer* m_renderer;
+};
+
+#define CHECK_GL_ERROR() { CheckGLErrorImpl (__FILE__, __LINE__); }
+void CheckGLErrorImpl (const char* file, int line);
--- a/src/glrenderer.cpp	Tue Feb 14 14:52:01 2017 +0200
+++ b/src/glrenderer.cpp	Tue Feb 14 14:53:06 2017 +0200
@@ -30,7 +30,7 @@
 #include "mainwindow.h"
 #include "miscallenous.h"
 #include "editHistory.h"
-#include "glCompiler.h"
+#include "glcompiler.h"
 #include "primitives.h"
 #include "documentmanager.h"
 #include "grid.h"
--- a/src/ldObject.cpp	Tue Feb 14 14:52:01 2017 +0200
+++ b/src/ldObject.cpp	Tue Feb 14 14:53:06 2017 +0200
@@ -25,7 +25,7 @@
 #include "editHistory.h"
 #include "canvas.h"
 #include "colors.h"
-#include "glCompiler.h"
+#include "glcompiler.h"
 #include "linetypes/edgeline.h"
 
 // List of all LDObjects
--- a/src/mainwindow.cpp	Tue Feb 14 14:52:01 2017 +0200
+++ b/src/mainwindow.cpp	Tue Feb 14 14:53:06 2017 +0200
@@ -35,7 +35,7 @@
 #include "dialogs/configdialog.h"
 #include "linetypes/comment.h"
 #include "guiutilities.h"
-#include "glCompiler.h"
+#include "glcompiler.h"
 #include "documentmanager.h"
 #include "ldobjectiterator.h"
 #include "grid.h"
--- a/src/toolsets/viewtoolset.cpp	Tue Feb 14 14:52:01 2017 +0200
+++ b/src/toolsets/viewtoolset.cpp	Tue Feb 14 14:53:06 2017 +0200
@@ -24,7 +24,7 @@
 #include "../canvas.h"
 #include "../primitives.h"
 #include "../colors.h"
-#include "../glCompiler.h"
+#include "../glcompiler.h"
 #include "../documentmanager.h"
 #include "viewtoolset.h"
 

mercurial