src/vertexcompiler.cpp

Fri, 27 Apr 2018 16:27:14 +0300

author
Teemu Piippo <teemu@hecknology.net>
date
Fri, 27 Apr 2018 16:27:14 +0300
changeset 1385
2f18c0da749d
permissions
-rw-r--r--

added vertex rendering

/*
 *  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 <http://www.gnu.org/licenses/>.
 */

#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<LDObject*>(this->sender()));
}

void VertexCompiler::handleModifiedObject()
{
	addVerticesFromObject(qobject_cast<LDObject*>(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<Vertex, unsigned int> 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);
}

mercurial