diff -r 4c134708be05 -r 2f18c0da749d src/vertexcompiler.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/vertexcompiler.cpp Fri Apr 27 16:27:14 2018 +0300
@@ -0,0 +1,267 @@
+/*
+ * LDForge: LDraw parts authoring CAD
+ * Copyright (C) 2013 - 2018 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 .
+ */
+
+#include "vertexcompiler.h"
+#include "vertexselection.h"
+#include "model.h"
+
+static const Vertex sphere[] = {
+ {1, 0, 0}, {0.7071, 0.7071, 0}, {0.7071, 0, 0.7071},
+ {0, 0.7071, 0.7071}, {0, 0, 1}, {0.7071, 0, 0.7071},
+ {0.7071, 0.7071, 0}, {0, 0.7071, 0.7071}, {0.7071, 0, 0.7071},
+ {0, 1, 0}, {0, 0.7071, 0.7071}, {0.7071, 0.7071, 0},
+ {0.7071, 0, -0.7071}, {0.7071, 0.7071, 0}, {1, 0, 0},
+ {0.7071, 0, -0.7071}, {0, 0, -1}, {0, 0.7071, -0.7071},
+ {0.7071, 0, -0.7071}, {0, 0.7071, -0.7071}, {0.7071, 0.7071, 0},
+ {0.7071, 0.7071, 0}, {0, 0.7071, -0.7071}, {0, 1, 0},
+ {-0.7071, 0, 0.7071}, {-0.7071, 0.7071, 0}, {-1, 0, 0},
+ {-0.7071, 0, 0.7071}, {0, 0, 1}, {0, 0.7071, 0.7071},
+ {-0.7071, 0, 0.7071}, {0, 0.7071, 0.7071}, {-0.7071, 0.7071, 0},
+ {-0.7071, 0.7071, 0}, {0, 0.7071, 0.7071}, {0, 1, 0},
+ {-1, 0, 0}, {-0.7071, 0.7071, 0}, {-0.7071, 0, -0.7071},
+ {0, 0.7071, -0.7071}, {0, 0, -1}, {-0.7071, 0, -0.7071},
+ {-0.7071, 0.7071, 0}, {0, 0.7071, -0.7071}, {-0.7071, 0, -0.7071},
+ {0, 1, 0}, {0, 0.7071, -0.7071}, {-0.7071, 0.7071, 0},
+ {-0.7071, 0, -0.7071}, {0, 0, -1}, {0, -0.7071, -0.7071},
+ {0, -1, 0}, {0, -0.7071, 0.7071}, {-0.7071, -0.7071, 0},
+ {0.7071, -0.7071, 0}, {0, -0.7071, -0.7071}, {0.7071, 0, -0.7071},
+ {-1, 0, 0}, {-0.7071, -0.7071, 0}, {-0.7071, 0, 0.7071},
+ {-0.7071, -0.7071, 0}, {0, -0.7071, -0.7071}, {0, -1, 0},
+ {0, -1, 0}, {0, -0.7071, -0.7071}, {0.7071, -0.7071, 0},
+ {0.7071, 0, 0.7071}, {0, -0.7071, 0.7071}, {0.7071, -0.7071, 0},
+ {-0.7071, 0, -0.7071}, {-0.7071, -0.7071, 0}, {-1, 0, 0},
+ {1, 0, 0}, {0.7071, -0.7071, 0}, {0.7071, 0, -0.7071},
+ {0.7071, 0, 0.7071}, {0, 0, 1}, {0, -0.7071, 0.7071},
+ {-0.7071, 0, -0.7071}, {0, -0.7071, -0.7071}, {-0.7071, -0.7071, 0},
+ {0.7071, -0.7071, 0}, {0, -0.7071, 0.7071}, {0, -1, 0},
+ {0.7071, 0, 0.7071}, {0.7071, -0.7071, 0}, {1, 0, 0},
+ {-0.7071, -0.7071, 0}, {0, -0.7071, 0.7071}, {-0.7071, 0, 0.7071},
+ {0, -0.7071, -0.7071}, {0, 0, -1}, {0.7071, 0, -0.7071},
+ {0, -0.7071, 0.7071}, {0, 0, 1}, {-0.7071, 0, 0.7071},
+};
+
+static const float sphereSize = 0.5;
+static const QColor sphereColor {192, 192, 255};
+
+VertexCompiler::VertexCompiler(Model* model, VertexSelection* selection, QObject* parent) :
+ QObject {parent},
+ model {model}
+{
+ connect(model, &Model::objectAdded, this, &VertexCompiler::handleNewObject);
+ connect(model, &Model::aboutToRemoveObject, this, &VertexCompiler::handleRemovedObject);
+
+ if (selection != nullptr)
+ {
+ this->connect(
+ selection,
+ &VertexSelection::vertexSelected,
+ this,
+ &VertexCompiler::updateVertex
+ );
+ this->connect(
+ selection,
+ &VertexSelection::vertexDeselected,
+ this,
+ &VertexCompiler::updateVertex
+ );
+ }
+}
+
+VertexCompiler::~VertexCompiler()
+{
+ if (this->initialized)
+ {
+ GLuint buffers[NumVbos];
+
+ for (int i = 0; i < countof(this->vbos); i += 1)
+ buffers[i] = this->vbos[i].buffer;
+
+ this->glDeleteBuffers(countof(buffers), &buffers[0]);
+ }
+}
+
+void VertexCompiler::handleNewObject(const QModelIndex &index)
+{
+ LDObject* object = this->model->lookup(index);
+ this->addVerticesFromObject(object);
+ connect(object, &LDObject::aboutToBeModified, this, &VertexCompiler::handlePreModifiedObject);
+ connect(object, &LDObject::modified, this, &VertexCompiler::handleModifiedObject);
+}
+
+void VertexCompiler::handleRemovedObject(const QModelIndex &index)
+{
+ LDObject* object = this->model->lookup(index);
+ this->removeVerticesFromObject(object);
+}
+
+void VertexCompiler::handlePreModifiedObject()
+{
+ removeVerticesFromObject(qobject_cast(this->sender()));
+}
+
+void VertexCompiler::handleModifiedObject()
+{
+ addVerticesFromObject(qobject_cast(this->sender()));
+}
+
+void VertexCompiler::initialize()
+{
+ if (not this->initialized)
+ {
+ this->initializeOpenGLFunctions();
+ this->initialized = true;
+ GLuint buffers[NumVbos];
+ this->glGenBuffers(countof(buffers), &buffers[0]);
+
+ for (int i = 0; i < countof(this->vbos); i += 1)
+ this->vbos[i].buffer = buffers[i];
+ }
+}
+
+void VertexCompiler::addVerticesFromObject(LDObject* object)
+{
+ for (int i = 0; i < object->numPolygonVertices(); i += 1)
+ this->addVertex(object->vertex(i));
+
+ this->needCompile = true;
+}
+
+void VertexCompiler::removeVerticesFromObject(LDObject* object)
+{
+ for (int i = 0; i < object->numPolygonVertices(); i += 1)
+ this->removeVertex(object->vertex(i));
+
+ this->needCompile = true;
+}
+
+void VertexCompiler::addVertex(const Vertex& vertex)
+{
+ auto iterator = this->vertices.find(vertex);
+
+ if (iterator == this->vertices.end())
+ this->vertices.insert(vertex, 1);
+ else
+ iterator.value() += 1;
+}
+
+void VertexCompiler::removeVertex(const Vertex& vertex)
+{
+ auto iterator = this->vertices.find(vertex);
+
+ if (iterator != this->vertices.end())
+ {
+ if (iterator.value() > 1)
+ iterator.value() -= 1;
+ else
+ this->vertices.erase(iterator);
+ }
+}
+
+void VertexCompiler::updateVertex(const Vertex&)
+{
+ this->needCompile = true;
+}
+
+/*
+ * Returns the GL buffer for the given vbo.
+ */
+GLuint VertexCompiler::vbo(Vbo vboIndex)
+{
+ if (this->needCompile)
+ {
+ this->compile();
+ this->upload();
+ this->needCompile = false;
+ }
+
+ return this->vbos[vboIndex].buffer;
+}
+
+/*
+ * Returns the size of the given vbo.
+ */
+size_t VertexCompiler::vboSize(Vbo vboIndex) const
+{
+ return this->vbos[vboIndex].data.size();
+}
+
+/*
+ * Clears the vertex scene.
+ */
+void VertexCompiler::clear()
+{
+ for (auto& vbo : this->vbos)
+ vbo.data.clear();
+}
+
+/*
+ * Builds the vertex scene
+ */
+void VertexCompiler::compile()
+{
+ this->clear();
+ QMapIterator iterator {this->vertices};
+
+ while (iterator.hasNext())
+ {
+ iterator.next();
+ this->compileVertex(iterator.key());
+ }
+}
+
+/*
+ * Adds a little sphere into the scene to represent the given vertex.
+ */
+void VertexCompiler::compileVertex(const Vertex& vertex)
+{
+ for (int i = 0; i < countof(::sphere); i += 1)
+ {
+ // Y and Z inverted like the rest of the scene
+ Vertex spherePoint = {
+ ::sphere[i][X] * ::sphereSize + vertex.x,
+ ::sphere[i][Y] * ::sphereSize - vertex.y,
+ ::sphere[i][Z] * ::sphereSize - vertex.z
+ };
+ this->vbos[Surfaces].data << spherePoint.x << spherePoint.y << spherePoint.z;
+ // The points of the sphere are position vectors, which in this case are also unit normals.
+ this->vbos[Normals].data << ::sphere[i][X] << ::sphere[i][Y] << ::sphere[i][Z];
+ this->vbos[Colors].data
+ << ::sphereColor.redF()
+ << ::sphereColor.greenF()
+ << ::sphereColor.blueF()
+ << ::sphereColor.alphaF();
+ }
+}
+
+/*
+ * Uploads VBO data to the graphics card.
+ */
+void VertexCompiler::upload()
+{
+ for (const auto& vbo : this->vbos)
+ {
+ glBindBuffer(GL_ARRAY_BUFFER, vbo.buffer);
+ glBufferData(
+ GL_ARRAY_BUFFER,
+ countof(vbo.data) * sizeof(GLfloat),
+ vbo.data.constData(),
+ GL_STATIC_DRAW
+ );
+ }
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+}