src/gl/compiler.cpp

changeset 189
815fbaae9cb2
parent 150
b6cbba6e29a1
child 193
b4beff48bb7a
--- a/src/gl/compiler.cpp	Tue May 24 16:11:10 2022 +0300
+++ b/src/gl/compiler.cpp	Wed May 25 12:01:58 2022 +0300
@@ -125,17 +125,6 @@
 }
 )";
 
-gl::Compiler::Compiler(Model *model, const ldraw::ColorTable& colorTable, QObject* parent) :
-	QObject{parent},
-	model{model},
-	colorTable{colorTable}
-{
-}
-
-gl::Compiler::~Compiler()
-{
-}
-
 void gl::buildShaders(
 	QOpenGLShaderProgram* shaderProgram,
 	const char* vertexShaderSource,
@@ -174,69 +163,40 @@
 	}
 }
 
-void gl::Compiler::initialize()
+void gl::initializeModelShaders(gl::ModelShaders *modelShaders)
 {
-	if (not this->initialized)
+	if (not modelShaders->initialized)
 	{
-		this->initializeOpenGLFunctions();
-		for (auto& object : this->glObjects)
+		for (auto& shader : modelShaders->shaderObjects)
 		{
-			object.program = new QOpenGLShaderProgram;
-			gl::buildShaders(object.program, ::vertexShaderSource, ::fragmentShaderSource);
-			object.program->bind();
-			object.buffer.create();
-			object.buffer.bind();
-			object.buffer.setUsagePattern(QOpenGLBuffer::DynamicDraw);
-			object.vertexArray.create();
-			object.vertexArray.bind();
+			shader.program = std::make_unique<QOpenGLShaderProgram>();
+			gl::buildShaders(shader.program.get(), ::vertexShaderSource, ::fragmentShaderSource);
+			shader.program->bind();
+			shader.buffer.create();
+			shader.buffer.bind();
+			shader.buffer.setUsagePattern(QOpenGLBuffer::DynamicDraw);
+			shader.vertexArray.create();
+			shader.vertexArray.bind();
 			for (int k : {0, 1, 2, 3, 4})
 			{
-				object.program->enableAttributeArray(k);
+				shader.program->enableAttributeArray(k);
 			}
+			using Vertex = ModelShaders::Vertex;
 			constexpr int stride = sizeof(Vertex);
-			object.program->setAttributeBuffer(0, GL_FLOAT, offsetof(Vertex, position), 3, stride);
-			object.program->setAttributeBuffer(1, GL_FLOAT, offsetof(Vertex, color), 4, stride);
-			object.program->setAttributeBuffer(2, GL_FLOAT, offsetof(Vertex, normal), 3, stride);
+			shader.program->setAttributeBuffer(0, GL_FLOAT, offsetof(Vertex, position), 3, stride);
+			shader.program->setAttributeBuffer(1, GL_FLOAT, offsetof(Vertex, color), 4, stride);
+			shader.program->setAttributeBuffer(2, GL_FLOAT, offsetof(Vertex, normal), 3, stride);
 			glVertexAttribIPointer(3, 1, GL_INT, stride, reinterpret_cast<void*>(offsetof(Vertex, id)));
 			glVertexAttribIPointer(4, 1, GL_INT, stride, reinterpret_cast<void*>(offsetof(Vertex, selected)));
-			object.vertexArray.release();
-			object.buffer.release();
-			object.program->release();
+			shader.vertexArray.release();
+			shader.buffer.release();
+			shader.program->release();
 		}
-		this->initialized = true;
+		modelShaders->initialized = true;
 	}
 }
 
-void gl::Compiler::build(DocumentManager* context, const gl::RenderPreferences& preferences)
-{
-	this->boundingBox = {};
-	std::vector<Vertex> vboData[gl::NUM_POLYGON_TYPES];
-	std::optional<ModelId> modelId = context->findIdForModel(this->model);
-	if (modelId.has_value())
-	{
-		PolygonCache* polygonBuilder = context->getPolygonCacheForModel(modelId.value());
-		if (polygonBuilder != nullptr)
-		{
-			const std::vector<gl::Polygon> polygons = polygonBuilder->getPolygons(context);
-			for (const gl::Polygon& polygon : polygons)
-			{
-				this->buildPolygon(polygon, vboData, preferences);
-			}
-			for (int arrayId = 0; arrayId < gl::NUM_POLYGON_TYPES; arrayId += 1)
-			{
-				auto& buffer = this->glObjects[arrayId].buffer;
-				auto& vector = vboData[arrayId];
-				this->storedVertexCounts[arrayId] = vector.size();
-				this->glObjects[arrayId].cachedData = vector; // todo: get rid of this copy
-				buffer.bind();
-				buffer.allocate(vector.data(), static_cast<int>(vector.size() * sizeof vector[0]));
-				buffer.release();
-			}
-		}
-	}
-}
-
-gl::ArrayClass classifyPolygon(const gl::Polygon& polygon)
+static gl::ArrayClass classifyPolygon(const gl::Polygon& polygon)
 {
 	switch (polygon.type)
 	{
@@ -252,36 +212,27 @@
 	return gl::ArrayClass::Lines;
 }
 
-ldraw::id_t gl::Compiler::idFromColor(const std::array<GLubyte, 3>& data)
-{
-	return {data[0] * std::int32_t{0x10000} + data[1] * std::int32_t{0x100} + data[2]};
-}
-
-void gl::Compiler::buildPolygon(
-	gl::Polygon polygon,
-	std::vector<Vertex>* vboData,
-	const gl::RenderPreferences& preferences)
+template<typename Fn>
+void iterateModelPolygons(Model* model, DocumentManager* context, Fn&& fn)
 {
-	const gl::ArrayClass vboClass = classifyPolygon(polygon);
-	std::vector<Vertex>& vertexBuffer = vboData[static_cast<int>(vboClass)];
-	auto vertexRing = iter::ring(polygon.vertices, polygon.numPolygonVertices());
-	reserveMore(vertexBuffer, polygon.numPolygonVertices());
-	const QColor color = this->getColorForPolygon(polygon, preferences);
-	for (unsigned int i = 0; i < polygon.numPolygonVertices(); i += 1)
+	std::optional<ModelId> modelId = context->findIdForModel(model);
+	if (modelId.has_value())
 	{
-		const glm::vec3& v1 = vertexRing[i - 1];
-		const glm::vec3& v2 = vertexRing[i];
-		const glm::vec3& v3 = vertexRing[i + 1];
-		this->boundingBox.consider(polygon.vertices[i]);
-		Vertex& vertex = vertexBuffer.emplace_back();
-		vertex.position = polygon.vertices[i];
-		vertex.normal = glm::normalize(glm::cross(v1 - v2, v3 - v2));
-		vertex.color = glm::vec4{color.redF(), color.greenF(), color.blueF(), color.alphaF()};
-		vertex.id = polygon.id.value;
+		PolygonCache* polygonCache= context->getPolygonCacheForModel(modelId.value());
+		if (polygonCache != nullptr)
+		{
+			for (const gl::Polygon& polygon : polygonCache->getPolygons(context))
+			{
+				fn(polygon);
+			}
+		}
 	}
 }
 
-QColor gl::Compiler::getColorForPolygon(const gl::Polygon& polygon, const gl::RenderPreferences& preferences)
+static QColor getColorForPolygon(
+	const gl::Polygon& polygon,
+	const gl::RenderPreferences& preferences,
+	const ldraw::ColorTable& colorTable)
 {
 	QColor color;
 	// For normal colors, use the polygon's color.
@@ -297,41 +248,94 @@
 	else
 	{
 		// Not main or edge color, use the polygon's color as is.
-		color = this->colorTable[polygon.color].faceColor;
+		color = colorTable[polygon.color].faceColor;
 	}
 	return color;
 }
 
-glm::vec3 gl::Compiler::modelCenter() const
+/**
+ * @brief Computes the minimum bounding box for a model
+ */
+BoundingBox gl::boundingBoxForModel(Model* model, DocumentManager* context)
 {
-	return boxCenter(this->boundingBox);
-}
-
-double gl::Compiler::modelDistance() const
-{
-	return static_cast<double>(longestMeasure(this->boundingBox));
+	BoundingBox result = emptyBoundingBox;
+	iterateModelPolygons(model, context, [&](const gl::Polygon& polygon)
+	{
+		for (unsigned int i = 0; i < polygon.numPolygonVertices(); i += 1)
+		{
+			addPointToBox(result, polygon.vertices[i]);
+		}
+	});
+	return result;
 }
 
-void gl::Compiler::bindVertexArray(gl::ArrayClass arrayClass)
+/**
+ * @brief gl::build Creates GL vertices for objects in the model and buffers them to shaders.
+ */
+void gl::build(
+	gl::ModelShaders* shaders,
+	Model* model,
+	const ldraw::ColorTable& colorTable,
+	DocumentManager* context,
+	const gl::RenderPreferences& preferences)
 {
-	auto& object = this->glObjects[static_cast<int>(arrayClass)];
-	object.vertexArray.bind();
-	object.program->bind();
+	for (gl::ModelShaders::ShaderObject& shader : shaders->shaderObjects) {
+		shader.cachedData.clear();
+	}
+	iterateModelPolygons(model, context, [&](const Polygon& polygon)
+	{
+		const int index = static_cast<int>(classifyPolygon(polygon));
+		std::vector<gl::ModelShaders::Vertex>& vertexBuffer = shaders->shaderObjects[index].cachedData;
+		auto vertexRing = iter::ring(polygon.vertices, polygon.numPolygonVertices());
+		reserveMore(vertexBuffer, polygon.numPolygonVertices());
+		const QColor color = getColorForPolygon(polygon, preferences, colorTable);
+		for (unsigned int i = 0; i < polygon.numPolygonVertices(); i += 1)
+		{
+			const glm::vec3& v1 = vertexRing[i - 1];
+			const glm::vec3& v2 = vertexRing[i];
+			const glm::vec3& v3 = vertexRing[i + 1];
+			gl::ModelShaders::Vertex& vertex = vertexBuffer.emplace_back();
+			vertex.position = polygon.vertices[i];
+			vertex.normal = glm::normalize(glm::cross(v1 - v2, v3 - v2));
+			vertex.color = glm::vec4{color.redF(), color.greenF(), color.blueF(), color.alphaF()};
+			vertex.id = polygon.id.value;
+		}
+	});
+	for (gl::ModelShaders::ShaderObject& shader : shaders->shaderObjects)
+	{
+		shader.vertexCount = shader.cachedData.size();
+		shader.buffer.bind();
+		const int bytes = static_cast<int>(shader.cachedData.size() * sizeof shader.cachedData[0]);
+		shader.buffer.allocate(shader.cachedData.data(), bytes);
+		shader.buffer.release();
+	}
 }
 
-void gl::Compiler::releaseVertexArray(gl::ArrayClass arrayClass)
+ldraw::id_t gl::idFromColor(const std::array<GLubyte, 3>& data)
 {
-	auto& object = this->glObjects[static_cast<int>(arrayClass)];
-	object.program->release();
-	object.vertexArray.release();
+	return {data[0] * std::int32_t{0x10000} + data[1] * std::int32_t{0x100} + data[2]};
+}
+
+void gl::bindModelShaderVertexArray(gl::ModelShaders* shaders, gl::ArrayClass arrayClass)
+{
+	ModelShaders::ShaderObject& shaderObject = shaders->shaderObjects[static_cast<int>(arrayClass)];
+	shaderObject.vertexArray.bind();
+	shaderObject.program->bind();
 }
 
-void gl::Compiler::setSelectedObjects(const QSet<ldraw::id_t> ids)
+void gl::releaseModelShaderVertexArray(gl::ModelShaders* shaders, gl::ArrayClass arrayClass)
 {
-	for (auto& object : this->glObjects)
+	ModelShaders::ShaderObject& shaderObject = shaders->shaderObjects[static_cast<int>(arrayClass)];
+	shaderObject.program->release();
+	shaderObject.vertexArray.release();
+}
+
+void gl::setModelShaderSelectedObjects(gl::ModelShaders* shaders, const QSet<ldraw::id_t>& ids)
+{
+	for (ModelShaders::ShaderObject& object : shaders->shaderObjects)
 	{
-		std::vector<Vertex>& vector = object.cachedData;
-		for (Vertex& vertex : vector)
+		std::vector<ModelShaders::Vertex>& vector = object.cachedData;
+		for (ModelShaders::Vertex& vertex : vector)
 		{
 			vertex.selected = (ids.contains({vertex.id})) ? 1 : 0;
 		}
@@ -342,7 +346,7 @@
 	}
 }
 
-std::size_t gl::Compiler::vertexCount(const gl::ArrayClass arrayClass) const
+std::size_t gl::vertexCount(const gl::ModelShaders* shaders, const gl::ArrayClass arrayClass)
 {
-	return this->storedVertexCounts[static_cast<int>(arrayClass)];
+	return shaders->shaderObjects[static_cast<int>(arrayClass)].vertexCount;
 }

mercurial