src/gl/compiler.cpp

changeset 26
3a9e761e4faa
parent 22
6da867fa5429
child 27
c57fb7a5ffa3
--- a/src/gl/compiler.cpp	Sun Jan 19 14:25:57 2020 +0200
+++ b/src/gl/compiler.cpp	Wed Jan 22 00:23:29 2020 +0200
@@ -19,27 +19,52 @@
 #define GL_GLEXT_PROTOTYPES
 #include <GL/glu.h>
 #include <GL/glext.h>
+#include <QMessageBox>
 #include "gl/compiler.h"
 #include "documentmanager.h"
 #include "invert.h"
 #include "ring.h"
 
-gl::Compiler::Compiler(QObject* parent) :
-	QObject{parent}
+gl::Compiler::Compiler(const ColorTable& colorTable, QObject* parent) :
+	QObject{parent},
+	colorTable{colorTable}
 {
 }
 
 gl::Compiler::~Compiler()
 {
+	if (this->initialized)
+	{
+		for (int arrayId = 0; arrayId < gl::NUM_ARRAY_CLASSES; arrayId += 1)
+		{
+			glDeleteProgram(this->glObjects[arrayId].program);
+			glDeleteShader(this->glObjects[arrayId].vertexShader);
+			glDeleteProgram(this->glObjects[arrayId].fragmentShader);
+		}
+	}
+}
 
+void gl::Compiler::initialize()
+{
+	if (not this->initialized)
+	{
+		this->initializeOpenGLFunctions();
+		for (int arrayId = 0; arrayId < gl::NUM_ARRAY_CLASSES; arrayId += 1)
+		{
+			QOpenGLVertexArrayObject& vao = this->vertexArrays[arrayId];
+			vao.create();
+			vao.bind();
+			glGenBuffers(gl::numVboSubclasses, &this->storedVbo[gl::numVboSubclasses * arrayId]);
+			this->buildShaders(arrayId);
+			vao.release();
+		}
+		//glGenBuffers(countof(this->storedVbo), &this->storedVbo[0]);
+		this->initialized = true;
+	}
 }
 
 void gl::Compiler::build(Model* model, DocumentManager* context)
 {
-	if (not this->initialized)
-	{
-		this->initializeVbo();
-	}
 	this->boundingBox = {};
 	std::vector<GLfloat> vboData[gl::numVbos];
 	const std::vector<gl::Polygon> polygons = model->getPolygons(context);
@@ -47,29 +72,41 @@
 	{
 		this->buildPolygon(polygon, vboData);
 	}
-	for (int i = 0; i < gl::numVbos; i += 1)
+	/*
+	for (int index = 0; index < gl::numVbos; index += 1)
+	{
+		this->upload(index, vboData[index]);
+	}*/
+	for (int arrayId = 0; arrayId < gl::NUM_ARRAY_CLASSES; arrayId += 1)
 	{
-		this->upload(i, vboData[i]);
+		this->vertexArrays[arrayId].bind();
+		for (int i = 0; i < gl::numVboSubclasses; i += 1)
+		{
+			const int vboIndex = gl::vboIndex({static_cast<gl::ArrayClass>(arrayId), static_cast<gl::VboSubclass>(i)});
+			this->upload(vboIndex, vboData[vboIndex]);
+		}
+		this->vertexArrays[arrayId].release();
 	}
 }
 
-gl::VboClass classifyPolygon(const gl::Polygon& polygon)
+gl::ArrayClass classifyPolygon(const gl::Polygon& polygon)
 {
 	switch (polygon.type)
 	{
 	case gl::Polygon::EdgeLine:
-		return gl::VboClass::Lines;
+		return gl::ArrayClass::Lines;
 	case gl::Polygon::Triangle:
-		return gl::VboClass::Triangles;
+		return gl::ArrayClass::Triangles;
 	case gl::Polygon::Quadrilateral:
-		return gl::VboClass::Quads;
+		return gl::ArrayClass::Quads;
 	case gl::Polygon::ConditionalEdge:
-		return gl::VboClass::ConditionalLines;
+		return gl::ArrayClass::ConditionalLines;
 	}
-	return gl::VboClass::Lines;
+	return gl::ArrayClass::Lines;
 }
 
-QColor colorFromId(linetypes::Id id)
+[[maybe_unused]]
+static QColor colorFromId(linetypes::Id id)
 {
 	// Calculate a color based from this index. This method caters for
 	// 16777216 objects. I don't think that will be exceeded anytime soon.
@@ -79,129 +116,62 @@
 	return {r, g, b};
 }
 
-void writeVertex(std::vector<GLfloat>& data, const Point3D& point)
-{
-	data.push_back(static_cast<GLfloat>(point.x));
-	data.push_back(static_cast<GLfloat>(point.y));
-	data.push_back(static_cast<GLfloat>(point.z));
-}
-
 void gl::Compiler::buildPolygon(gl::Polygon polygon, std::vector<GLfloat>* vboData)
 {
-	const gl::VboClass vboClass = classifyPolygon(polygon);
-	auto vboBuffer = [&](VboSubclass subclass) -> std::vector<GLfloat>&
-	{
-		return vboData[gl::vboIndex({vboClass, subclass})];
-	};
+	const gl::ArrayClass vboClass = classifyPolygon(polygon);
+	std::vector<GLfloat>& vertexBuffer = vboData[gl::vboIndex({vboClass, gl::VboSubclass::VertexData})];
+	std::vector<GLfloat>& normalsBuffer = vboData[gl::vboIndex({vboClass, gl::VboSubclass::Normals})];
 	auto vertexRing = iter::ring(polygon.vertices, polygon.numPolygonVertices());
+	reserveMore(normalsBuffer, polygon.numPolygonVertices() * 3_z);
 	for (unsigned int i = 0; i < polygon.numPolygonVertices(); i += 1)
 	{
 		const Point3D& v1 = vertexRing[i - 1];
 		const Point3D& v2 = vertexRing[i];
 		const Point3D& v3 = vertexRing[i + 1];
 		const QVector3D normal = QVector3D::crossProduct(v3 - v2, v1 - v2).normalized();
-		std::vector<GLfloat>& data = vboBuffer(VboSubclass::Normals);
 		for (const GLfloat coord : {normal.x(), normal.y(), normal.z()})
-			data.push_back(coord);
+			normalsBuffer.push_back(coord);
 	}
-	vboBuffer(VboSubclass::Surfaces).reserve(vboBuffer(VboSubclass::Surfaces).size() + polygon.numPolygonVertices());
+	reserveMore(vertexBuffer, polygon.numPolygonVertices() * 7);
+	const QColor color = this->getColorForPolygon(polygon);
 	// Transform vertices so that they're suitable for GL rendering
 	for (unsigned int i = 0; i < polygon.numPolygonVertices(); i += 1)
 	{
+		Point3D& point = polygon.vertices[i];
 		polygon.vertices[i].y = -polygon.vertices[i].y;
 		polygon.vertices[i].z = -polygon.vertices[i].z;
 		this->boundingBox.consider(polygon.vertices[i]);
-		writeVertex(vboBuffer(VboSubclass::Surfaces), polygon.vertices[i]);
+		vertexBuffer.push_back(static_cast<GLfloat>(point.x));
+		vertexBuffer.push_back(static_cast<GLfloat>(point.y));
+		vertexBuffer.push_back(static_cast<GLfloat>(point.z));
+		vertexBuffer.push_back(static_cast<GLfloat>(color.redF()));
+		vertexBuffer.push_back(static_cast<GLfloat>(color.greenF()));
+		vertexBuffer.push_back(static_cast<GLfloat>(color.blueF()));
+		vertexBuffer.push_back(static_cast<GLfloat>(color.alphaF()));
 	}
-	this->writeColor(vboData, polygon, VboSubclass::RegularColors);
-	this->writeColor(vboData, polygon, VboSubclass::PickColors);
-	this->writeColor(vboData, polygon, VboSubclass::BfcFrontColors);
-	this->writeColor(vboData, polygon, VboSubclass::BfcBackColors);
 }
 
-QColor gl::Compiler::getColorForPolygon(const gl::Polygon& polygon, VboSubclass subclass)
+QColor gl::Compiler::getColorForPolygon(const gl::Polygon& polygon)
 {
 	QColor color;
-
-	switch (subclass)
+	// For normal colors, use the polygon's color.
+	if (polygon.color == colors::main)
 	{
-	case VboSubclass::Surfaces:
-	case VboSubclass::Normals:
-	case VboSubclass::InvertedNormals:
-		// 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, use unique picking colors provided by the model.
-		return colorFromId(polygon.id);
-	case VboSubclass::RandomColors:
-		// For the random color scene, the owner object has rolled up a random color. Use that.
-		color = {255, 64, 255}; // polygonOwner->randomColor();
-		break;
-	case VboSubclass::RegularColors:
-		// For normal colors, use the polygon's color.
-		if (polygon.color == colors::main)
-		{
-			color = {255, 255, 64}; // mainColorRepresentation();
-		}
-		else if (polygon.color == colors::edge)
-		{
-			// Edge color is black, unless we have a dark background, in which case lines need to be bright.
-			color = Qt::black; //luma(config::backgroundColor()) > 40 ? Qt::black : Qt::white;
-		}
-		else
-		{
-			// Not main or edge color, use the polygon's color as is.
-			color = {255, 255, 64}; //polygon.color.faceColor();
-		}
-		break;
+		color = {255, 255, 64}; // mainColorRepresentation();
 	}
-
-	if (color.isValid())
+	else if (polygon.color == colors::edge)
 	{
-		// We may wish to apply blending on the color to indicate selection or highlight.
-		/*
-		const double blendAlpha = 0.0;
-		if (blendAlpha != 0.0)
-		{
-			QColor selectedColor = 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);
-		}
-		*/
+		// Edge color is black, unless we have a dark background, in which case lines need to be bright.
+		color = Qt::black; //luma(config::backgroundColor()) > 40 ? Qt::black : Qt::white;
 	}
 	else
 	{
-		if (polygon.numPolygonVertices() == 2)
-			color = Qt::black;
-		else
-			color = {255, 255, 64};
+		// Not main or edge color, use the polygon's color as is.
+		color = this->colorTable[polygon.color].faceColor;
 	}
-
 	return color;
 }
 
-void gl::Compiler::writeColor(std::vector<GLfloat>* data, const gl::Polygon& polygon, VboSubclass subclass)
-{
-	std::vector<GLfloat>& buffer = data[gl::vboIndex({classifyPolygon(polygon), subclass})];
-	const QColor color = this->getColorForPolygon(polygon, subclass);
-	buffer.reserve(data->size() + 4 * polygon.numPolygonVertices());
-	for (unsigned int i = 0; i < polygon.numPolygonVertices(); i += 1)
-	{
-		buffer.push_back(static_cast<GLfloat>(color.redF()));
-		buffer.push_back(static_cast<GLfloat>(color.greenF()));
-		buffer.push_back(static_cast<GLfloat>(color.blueF()));
-		buffer.push_back(static_cast<GLfloat>(color.alphaF()));
-	}
-}
-
 Point3D gl::Compiler::modelCenter() const
 {
 	return boxCenter(this->boundingBox);
@@ -212,11 +182,54 @@
 	return longestMeasure(this->boundingBox);
 }
 
-void gl::Compiler::initializeVbo()
+void gl::Compiler::bindVertexArray(gl::ArrayClass arrayClass)
+{
+	this->vertexArrays[static_cast<int>(arrayClass)].bind();
+	glUseProgram(this->glObjects[static_cast<int>(arrayClass)].program);
+}
+
+void gl::Compiler::releaseVertexArray(gl::ArrayClass arrayClass)
+{
+	this->vertexArrays[static_cast<int>(arrayClass)].release();
+}
+
+void gl::Compiler::buildShaders(int arrayId)
 {
-	this->initializeOpenGLFunctions();
-	glGenBuffers(countof(this->storedVbo), &this->storedVbo[0]);
-	this->initialized = true;
+	/*
+	this->glObjects[arrayId].vertexShader = glCreateShader(GL_VERTEX_SHADER);
+	glShaderSource(this->glObjects[arrayId].vertexShader, 1, &vertexShaderSource, nullptr);
+	glCompileShader(this->glObjects[arrayId].vertexShader);
+	this->glObjects[arrayId].fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
+	glShaderSource(this->glObjects[arrayId].fragmentShader, 1, &fragmentShaderSource, nullptr);
+	glCompileShader(this->glObjects[arrayId].fragmentShader);
+	for (auto&& pair : {
+		std::make_pair(this->glObjects[arrayId].vertexShader, tr("vertex shader")),
+		std::make_pair(this->glObjects[arrayId].fragmentShader, tr("fragment shader")),
+	})
+	{
+		GLint status;
+		glGetShaderiv(this->glObjects[arrayId].fragmentShader, GL_COMPILE_STATUS, &status);
+		if (status != GL_TRUE)
+		{
+			char compileLog[512];
+			glGetShaderInfoLog(pair.first, countof(compileLog), nullptr, compileLog);
+			QMessageBox::critical(nullptr, tr("Shader compile error"), tr("Unable to compile the %1. Compile log:\n\n%2").arg(pair.second).arg(compileLog));
+			abort();
+		}
+	}
+	this->glObjects[arrayId].program = glCreateProgram();
+	glAttachShader(this->glObjects[arrayId].program, this->glObjects[arrayId].vertexShader);
+	glAttachShader(this->glObjects[arrayId].program, this->glObjects[arrayId].fragmentShader);
+	glLinkProgram(this->glObjects[arrayId].program);
+	glUseProgram(this->glObjects[arrayId].program);
+	const std::size_t size = gl::FLOATS_PER_VERTEX * sizeof(GLfloat);
+	const GLuint posAttrib = static_cast<GLuint>(glGetAttribLocation(this->glObjects[arrayId].program, "position"));
+	glEnableVertexAttribArray(posAttrib);
+	glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, size, gl::offset(0));
+	const GLuint colAttrib = static_cast<GLuint>(glGetAttribLocation(this->glObjects[arrayId].program, "color"));
+	glEnableVertexAttribArray(colAttrib);
+	glVertexAttribPointer(colAttrib, 4, GL_FLOAT, GL_FALSE, size, gl::offset(3 * sizeof(GLfloat)));
+	*/
 }
 
 ///
@@ -228,7 +241,6 @@
 {
 	glBindBuffer(GL_ARRAY_BUFFER, this->storedVbo[vboIndex]);
 	glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizeiptr>(data.size() * sizeof data[0]), data.data(), GL_STATIC_DRAW);
-	glBindBuffer(GL_ARRAY_BUFFER, 0);
 	this->storedVboSizes[vboIndex] = data.size();
 }
 

mercurial