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); +}