Add vertex rendering

Tue, 27 Jul 2021 16:29:00 +0300

author
Teemu Piippo <teemu@hecknology.net>
date
Tue, 27 Jul 2021 16:29:00 +0300
changeset 118
8e1c9f18ae15
parent 117
121a40d5e34c
child 119
24275a4064f4

Add vertex rendering

CMakeLists.txt file | annotate | diff | comparison | revisions
src/document.cpp file | annotate | diff | comparison | revisions
src/document.h file | annotate | diff | comparison | revisions
src/gl/axesprogram.cpp file | annotate | diff | comparison | revisions
src/gl/axesprogram.h file | annotate | diff | comparison | revisions
src/gl/basicshaderprogram.cpp file | annotate | diff | comparison | revisions
src/gl/basicshaderprogram.h file | annotate | diff | comparison | revisions
src/gl/gridprogram.cpp file | annotate | diff | comparison | revisions
src/gl/gridprogram.h file | annotate | diff | comparison | revisions
src/gl/vertexprogram.cpp file | annotate | diff | comparison | revisions
src/gl/vertexprogram.h file | annotate | diff | comparison | revisions
src/ui/canvas.cpp file | annotate | diff | comparison | revisions
src/ui/canvas.h file | annotate | diff | comparison | revisions
src/vertexmap.cpp file | annotate | diff | comparison | revisions
src/vertexmap.h file | annotate | diff | comparison | revisions
--- a/CMakeLists.txt	Tue Jul 27 13:23:34 2021 +0300
+++ b/CMakeLists.txt	Tue Jul 27 16:29:00 2021 +0300
@@ -48,6 +48,7 @@
 	src/gl/compiler.cpp
 	src/gl/gridprogram.cpp
 	src/gl/partrenderer.cpp
+	src/gl/vertexprogram.cpp
 	src/linetypes/comment.cpp
 	src/linetypes/conditionaledge.cpp
 	src/linetypes/edge.cpp
@@ -101,6 +102,7 @@
 	src/gl/compiler.h
 	src/gl/gridprogram.h
 	src/gl/partrenderer.h
+	src/gl/vertexprogram.h
 	src/linetypes/comment.h
 	src/linetypes/conditionaledge.h
 	src/linetypes/edge.h
--- a/src/document.cpp	Tue Jul 27 13:23:34 2021 +0300
+++ b/src/document.cpp	Tue Jul 27 16:29:00 2021 +0300
@@ -31,10 +31,10 @@
 	model{model},
 	documents{documents},
 	colorTable{colorTable},
+	vertexMap{model},
 	renderer{new Canvas{model, documents, colorTable, this}},
 	ui{*new Ui::Document},
-	objectEditor{model, ldraw::NULL_ID, this},
-	vertexMap{model}
+	objectEditor{model, ldraw::NULL_ID, this}
 {
 	this->ui.setupUi(this);
 	this->ui.listView->setModel(model);
@@ -81,6 +81,10 @@
 	{
 		Q_EMIT this->mouseMove(this, canvas);
 	});
+	connect(&this->vertexMap, &VertexMap::verticesChanged, [&]()
+	{
+		this->renderer->rebuildVertices(this);
+	});
 }
 
 Document::~Document()
@@ -113,6 +117,11 @@
 	return this->model->edit();
 }
 
+void Document::applyToVertices(VertexMap::ApplyFunction fn) const
+{
+	this->vertexMap.apply(fn);
+}
+
 void Document::selectionChanged(const QSet<ldraw::id_t>& newSelection)
 {
 	if (newSelection.size() == 1)
--- a/src/document.h	Tue Jul 27 13:23:34 2021 +0300
+++ b/src/document.h	Tue Jul 27 16:29:00 2021 +0300
@@ -44,6 +44,7 @@
 	void setRenderPreferences(const gl::RenderPreferences& newPreferences);
 	void setCanvasOverpaintCallback(Canvas::OverpaintCallback fn);
 	Model::EditContext editModel();
+	void applyToVertices(VertexMap::ApplyFunction fn) const;
 Q_SIGNALS:
 	void newStatusText(const QString& newStatusText);
 	void splitterChanged();
@@ -54,8 +55,8 @@
 	Model* model;
 	DocumentManager* const documents;
 	const ldraw::ColorTable& colorTable;
+	VertexMap vertexMap;
 	Canvas* renderer;
 	Ui::Document& ui;
 	ObjectEditor objectEditor;
-	VertexMap vertexMap;
 };
--- a/src/gl/axesprogram.cpp	Tue Jul 27 13:23:34 2021 +0300
+++ b/src/gl/axesprogram.cpp	Tue Jul 27 16:29:00 2021 +0300
@@ -112,3 +112,8 @@
 	this->program->setAttributeBuffer(0, GL_FLOAT, offsetof(AxesVertex, position), 3, stride);
 	this->program->setAttributeBuffer(1, GL_FLOAT, offsetof(AxesVertex, color), 3, stride);
 }
+
+QOpenGLBuffer::UsagePattern AxesProgram::usagePattern() const
+{
+	return QOpenGLBuffer::StaticDraw;
+}
--- a/src/gl/axesprogram.h	Tue Jul 27 13:23:34 2021 +0300
+++ b/src/gl/axesprogram.h	Tue Jul 27 16:29:00 2021 +0300
@@ -15,4 +15,5 @@
 	int vertexSize() const override;
 	int vertexCount() const override;
 	void setupVertexArrays() override;
+	QOpenGLBuffer::UsagePattern usagePattern() const override;
 };
--- a/src/gl/basicshaderprogram.cpp	Tue Jul 27 13:23:34 2021 +0300
+++ b/src/gl/basicshaderprogram.cpp	Tue Jul 27 16:29:00 2021 +0300
@@ -37,8 +37,12 @@
 		this->program->bind();
 		this->buffer.create();
 		this->buffer.bind();
-		this->buffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
-		this->buffer.allocate(this->vertexData(), this->vertexCount() * this->vertexSize());
+		const QOpenGLBuffer::UsagePattern pattern = this->usagePattern();
+		this->buffer.setUsagePattern(pattern);
+		if (pattern == QOpenGLBuffer::StaticDraw)
+		{
+			this->buffer.allocate(this->vertexData(), this->vertexCount() * this->vertexSize());
+		}
 		this->vertexArrayObject.create();
 		this->vertexArrayObject.bind();
 		this->setupVertexArrays();
--- a/src/gl/basicshaderprogram.h	Tue Jul 27 13:23:34 2021 +0300
+++ b/src/gl/basicshaderprogram.h	Tue Jul 27 16:29:00 2021 +0300
@@ -37,6 +37,7 @@
 	virtual void setupVertexArrays() = 0;
 	// \returns what kind of elements are drawn (GL_QUADS, GL_TRIANGLES, GL_LINES, etc)
 	virtual GLenum drawMode() const = 0;
+	virtual QOpenGLBuffer::UsagePattern usagePattern() const = 0;
 	bool isInitialized = false;
 	QOpenGLBuffer buffer;
 	QOpenGLShader vertexShader;
--- a/src/gl/gridprogram.cpp	Tue Jul 27 13:23:34 2021 +0300
+++ b/src/gl/gridprogram.cpp	Tue Jul 27 16:29:00 2021 +0300
@@ -121,3 +121,8 @@
 {
 	return GL_QUADS;
 }
+
+QOpenGLBuffer::UsagePattern GridProgram::usagePattern() const
+{
+	return QOpenGLBuffer::StaticDraw;
+}
--- a/src/gl/gridprogram.h	Tue Jul 27 13:23:34 2021 +0300
+++ b/src/gl/gridprogram.h	Tue Jul 27 16:29:00 2021 +0300
@@ -35,6 +35,7 @@
 	int vertexCount() const override;
 	void setupVertexArrays() override;
 	GLenum drawMode() const override;
+	QOpenGLBuffer::UsagePattern usagePattern() const override;
 private:
 	glm::vec4 gridColor = {1.0f, 1.0f, 1.0f, 0.75f};
 };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gl/vertexprogram.cpp	Tue Jul 27 16:29:00 2021 +0300
@@ -0,0 +1,115 @@
+#include "vertexprogram.h"
+#include "document.h"
+
+static const char vertexShaderSource[] = R"(
+#version 330 core
+
+layout (location = 0) in vec3 in_position;
+layout (location = 1) in vec3 in_color;
+uniform mat4 view;
+uniform mat4 projection;
+uniform mat4 model;
+smooth out vec3 ex_color;
+
+void main()
+{
+	gl_Position = projection * view * model * vec4(in_position, 1.0);
+	ex_color = in_color;
+}
+)";
+
+static const char fragmentShaderSource[] = R"(
+#version 330 core
+
+out vec4 color;
+smooth in vec3 ex_color;
+
+void main(void)
+{
+	color = vec4(ex_color, 1);
+}
+)";
+
+static constexpr int VERTICES_PER_OBJECT = 16;
+
+
+VertexProgram::VertexProgram(QObject *parent) :
+	AbstractBasicShaderProgram{parent}
+{
+}
+
+const char *VertexProgram::vertexShaderSource() const
+{
+	return ::vertexShaderSource;
+}
+
+const char *VertexProgram::fragmentShaderSource() const
+{
+	return ::fragmentShaderSource;
+}
+
+const void *VertexProgram::vertexData() const
+{
+	return this->data.data();
+}
+
+int VertexProgram::vertexSize() const
+{
+	return sizeof(Vertex);
+}
+
+int VertexProgram::vertexCount() const
+{
+	return this->data.size();
+}
+
+void VertexProgram::setupVertexArrays()
+{
+	for (int i : {0, 1})
+	{
+		this->program->enableAttributeArray(i);
+	}
+	const int stride = this->vertexSize();
+	this->program->setAttributeBuffer(0, GL_FLOAT, offsetof(Vertex, position), 3, stride);
+	this->program->setAttributeBuffer(1, GL_FLOAT, offsetof(Vertex, color), 3, stride);
+}
+
+GLenum VertexProgram::drawMode() const
+{
+	return GL_LINES;
+}
+
+QOpenGLBuffer::UsagePattern VertexProgram::usagePattern() const
+{
+	return QOpenGLBuffer::DynamicDraw;
+}
+
+void VertexProgram::build(const Document *document)
+{
+	constexpr float size = 1;
+	constexpr glm::vec3 color = {0.0, 1.0, 1.0};
+	this->data.clear();
+	document->applyToVertices([&](const glm::vec3& vertex, const std::set<ldraw::id_t>&)
+	{
+		reserveMore(this->data, VERTICES_PER_OBJECT);
+		this->data.push_back({vertex, color});
+		this->data.push_back({vertex + glm::vec3{size, -size, size}, color});
+		this->data.push_back({vertex, color});
+		this->data.push_back({vertex + glm::vec3{size, -size, -size}, color});
+		this->data.push_back({vertex, color});
+		this->data.push_back({vertex + glm::vec3{-size, -size, -size}, color});
+		this->data.push_back({vertex, color});
+		this->data.push_back({vertex + glm::vec3{-size, -size, size}, color});
+		this->data.push_back({vertex + glm::vec3{size, -size, size}, color});
+		this->data.push_back({vertex + glm::vec3{size, -size, -size}, color});
+		this->data.push_back({vertex + glm::vec3{size, -size, -size}, color});
+		this->data.push_back({vertex + glm::vec3{-size, -size, -size}, color});
+		this->data.push_back({vertex + glm::vec3{-size, -size, -size}, color});
+		this->data.push_back({vertex + glm::vec3{-size, -size, size}, color});
+		this->data.push_back({vertex + glm::vec3{-size, -size, size}, color});
+		this->data.push_back({vertex + glm::vec3{size, -size, size}, color});
+	});
+	this->buffer.bind();
+	this->buffer.allocate(this->vertexData(), this->vertexCount() * this->vertexSize());
+	this->buffer.release();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gl/vertexprogram.h	Tue Jul 27 16:29:00 2021 +0300
@@ -0,0 +1,29 @@
+#ifndef VERTEXPROGRAM_H
+#define VERTEXPROGRAM_H
+#include "basicshaderprogram.h"
+class Document;
+
+class VertexProgram : public AbstractBasicShaderProgram
+{
+public:
+	struct Vertex
+	{
+		glm::vec3 position;
+		glm::vec3 color;
+	};
+	VertexProgram(QObject* parent = nullptr);
+	void build(const Document* document);
+protected:
+	const char* vertexShaderSource() const override;
+	const char* fragmentShaderSource() const override;
+	const void* vertexData() const override;
+	int vertexSize() const override;
+	int vertexCount() const override;
+	void setupVertexArrays() override;
+	GLenum drawMode() const override;
+	QOpenGLBuffer::UsagePattern usagePattern() const override;
+private:
+	std::vector<Vertex> data;
+};
+
+#endif // VERTEXPROGRAM_H
--- a/src/ui/canvas.cpp	Tue Jul 27 13:23:34 2021 +0300
+++ b/src/ui/canvas.cpp	Tue Jul 27 16:29:00 2021 +0300
@@ -21,6 +21,15 @@
 	this->update();
 }
 
+void Canvas::rebuildVertices(Document* document)
+{
+	if (this->vertexProgram.has_value())
+	{
+		this->vertexProgram->build(document);
+		this->update();
+	}
+}
+
 void Canvas::mouseMoveEvent(QMouseEvent* event)
 {
 	const ldraw::id_t id = this->pick(event->pos());
@@ -105,9 +114,12 @@
 	this->gridProgram->initialize();
 	this->axesProgram.emplace(this);
 	this->axesProgram->initialize();
+	this->vertexProgram.emplace(this);
+	this->vertexProgram->initialize();
 	for (AbstractBasicShaderProgram* program : {
 		static_cast<AbstractBasicShaderProgram*>(&*this->gridProgram),
 		static_cast<AbstractBasicShaderProgram*>(&*this->axesProgram),
+		static_cast<AbstractBasicShaderProgram*>(&*this->vertexProgram),
 	})
 	{
 		connect(this, &PartRenderer::projectionMatrixChanged,
@@ -156,6 +168,14 @@
 			this->gridProgram->draw();
 			glDisable(GL_BLEND);
 		}
+		// Render vertices
+		{
+			glLineWidth(2);
+			glEnable(GL_LINE_SMOOTH);
+			glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
+			this->vertexProgram->draw();
+			glDisable(GL_LINE_SMOOTH);
+		}
 		if (this->worldPosition.has_value())
 		{
 			QPainter painter{this};
--- a/src/ui/canvas.h	Tue Jul 27 13:23:34 2021 +0300
+++ b/src/ui/canvas.h	Tue Jul 27 16:29:00 2021 +0300
@@ -5,6 +5,7 @@
 #include "gl/partrenderer.h"
 #include "gl/gridprogram.h"
 #include "gl/axesprogram.h"
+#include "gl/vertexprogram.h"
 
 class Canvas : public PartRenderer
 {
@@ -24,6 +25,7 @@
 	const std::optional<glm::vec3>& getWorldPosition() const;
 public Q_SLOTS:
 	void handleSelectionChange(const QSet<ldraw::id_t>& selectedIds, const QSet<ldraw::id_t>& deselectedIds);
+	void rebuildVertices(Document *document);
 protected:
 	void mouseMoveEvent(QMouseEvent* event) override;
 	void mousePressEvent(QMouseEvent* event) override;
@@ -41,6 +43,7 @@
 	bool isGridPerpendicularToScreen(float threshold) const;
 	std::optional<GridProgram> gridProgram;
 	std::optional<AxesProgram> axesProgram;
+	std::optional<VertexProgram> vertexProgram;
 	std::optional<glm::vec3> worldPosition;
 	glm::mat4 gridMatrix;
 	geom::Plane gridPlane;
--- a/src/vertexmap.cpp	Tue Jul 27 13:23:34 2021 +0300
+++ b/src/vertexmap.cpp	Tue Jul 27 16:29:00 2021 +0300
@@ -28,12 +28,29 @@
 void VertexMap::build()
 {
 	this->map.clear();
+	this->vertices.clear();
 	this->model->apply<ldraw::Object>([&](const ldraw::Object* object)
 	{
 		for (int i = 0; i < object->numPoints(); i += 1)
 		{
 			const glm::vec3& point = object->getPoint(i);
-			this->map[qHash(point)].insert(object->id);
+			const unsigned int hash = qHash(point);
+			this->map[hash].insert(object->id);
+			this->vertices[hash] = point;
 		}
 	});
+	Q_EMIT this->verticesChanged();
 }
+
+/**
+ * @brief Apply \c fn for all vertices in the map.
+ * @param fn
+ */
+void VertexMap::apply(ApplyFunction fn) const
+{
+	for (auto it = this->map.cbegin(); it != this->map.cend(); ++it)
+	{
+		const glm::vec3& point = this->vertices.at(it->first);
+		fn(point, it->second);
+	}
+}
--- a/src/vertexmap.h	Tue Jul 27 13:23:34 2021 +0300
+++ b/src/vertexmap.h	Tue Jul 27 16:29:00 2021 +0300
@@ -4,14 +4,22 @@
 #include "main.h"
 #include "model.h"
 
+/**
+ * @brief Collects a map of all vertices in a model to all objects that use the specified vertex.
+ */
 class VertexMap : public QObject
 {
 	Q_OBJECT
 public:
+	using ApplyFunction = std::function<void(const glm::vec3&, const std::set<ldraw::id_t>&)>;
 	VertexMap(const Model *model);
 	Q_SLOT void build();
+	void apply(ApplyFunction fn) const;
+Q_SIGNALS:
+	Q_SIGNAL void verticesChanged();
 private:
 	const Model* const model;
+	std::map<unsigned int, glm::vec3> vertices;
 	std::map<unsigned int, std::set<ldraw::id_t>> map;
 };
 

mercurial