Tue, 14 Feb 2017 14:53:06 +0200
Renamed glCompiler.cpp → glcompiler.cpp
CMakeLists.txt | file | annotate | diff | comparison | revisions | |
src/glCompiler.cpp | file | annotate | diff | comparison | revisions | |
src/glCompiler.h | file | annotate | diff | comparison | revisions | |
src/glcompiler.cpp | file | annotate | diff | comparison | revisions | |
src/glcompiler.h | file | annotate | diff | comparison | revisions | |
src/glrenderer.cpp | file | annotate | diff | comparison | revisions | |
src/ldObject.cpp | file | annotate | diff | comparison | revisions | |
src/mainwindow.cpp | file | annotate | diff | comparison | revisions | |
src/toolsets/viewtoolset.cpp | file | annotate | diff | comparison | revisions |
--- a/CMakeLists.txt Tue Feb 14 14:52:01 2017 +0200 +++ b/CMakeLists.txt Tue Feb 14 14:53:06 2017 +0200 @@ -36,7 +36,7 @@ src/documentmanager.cpp src/editHistory.cpp src/glcamera.cpp - src/glCompiler.cpp + src/glcompiler.cpp src/glrenderer.cpp src/grid.cpp src/guiutilities.cpp @@ -98,7 +98,7 @@ src/editHistory.h src/format.h src/glcamera.h - src/glCompiler.h + src/glcompiler.h src/glrenderer.h src/grid.h src/guiutilities.h
--- a/src/glCompiler.cpp Tue Feb 14 14:52:01 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,432 +0,0 @@ -/* - * LDForge: LDraw parts authoring CAD - * Copyright (C) 2013 - 2017 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/>. - */ - -#define GL_GLEXT_PROTOTYPES -#include <GL/glu.h> -#include <GL/glext.h> -#include "glCompiler.h" -#include "miscallenous.h" -#include "guiutilities.h" -#include "documentmanager.h" -#include "grid.h" - -struct GLErrorInfo -{ - GLenum value; - QString text; -}; - -static const GLErrorInfo g_GLErrors[] = -{ - { GL_NO_ERROR, "No error" }, - { GL_INVALID_ENUM, "Unacceptable enumerator passed" }, - { GL_INVALID_VALUE, "Numeric argument out of range" }, - { GL_INVALID_OPERATION, "The operation is not allowed to be done in this state" }, - { GL_INVALID_FRAMEBUFFER_OPERATION, "Framebuffer object is not complete"}, - { GL_OUT_OF_MEMORY, "Out of memory" }, - { GL_STACK_UNDERFLOW, "The operation would have caused an underflow" }, - { GL_STACK_OVERFLOW, "The operation would have caused an overflow" }, -}; - -void CheckGLErrorImpl (const char* file, int line) -{ - QString errmsg; - GLenum errnum = glGetError(); - - if (errnum == GL_NO_ERROR) - return; - - for (const GLErrorInfo& err : g_GLErrors) - { - if (err.value == errnum) - { - errmsg = err.text; - break; - } - } - - print ("OpenGL ERROR: at %1:%2: %3", Basename (QString (file)), line, errmsg); -} - - -GLCompiler::GLCompiler (GLRenderer* renderer) : - HierarchyElement (renderer), - m_renderer (renderer) -{ - connect(renderer->model(), SIGNAL(objectAdded(LDObject*)), this, SLOT(compileObject(LDObject*))); - connect(renderer->model(), SIGNAL(objectModified(LDObject*)), this, SLOT(compileObject(LDObject*))); - connect(renderer->model(), SIGNAL(aboutToRemoveObject(LDObject*)), this, SLOT(forgetObject(LDObject*)), Qt::DirectConnection); - connect(renderer, SIGNAL(objectHighlightingChanged(LDObject*)), this, SLOT(compileObject(LDObject*))); - connect(m_window, SIGNAL(gridChanged()), this, SLOT(recompile())); - - for (LDObject* object : renderer->model()->objects()) - stageForCompilation(object); -} - - -void GLCompiler::initialize() -{ - initializeOpenGLFunctions(); - glGenBuffers (NumVbos, &m_vbo[0]); - CHECK_GL_ERROR(); -} - - -GLCompiler::~GLCompiler() -{ - glDeleteBuffers (NumVbos, &m_vbo[0]); - CHECK_GL_ERROR(); -} - - -QColor GLCompiler::indexColorForID (int id) const -{ - // Calculate a color based from this index. This method caters for - // 16777216 objects. I don't think that will be exceeded anytime soon. :) - int r = (id / 0x10000) % 0x100; - int g = (id / 0x100) % 0x100; - int b = id % 0x100; - return {r, g, b}; -} - -/* - * Returns the suitable color for the polygon. - * - polygon is the polygon to colorise. - * - polygonOwner is the LDObject from which the polygon originated. - * - subclass provides context for the polygon. - */ -QColor GLCompiler::getColorForPolygon(LDPolygon& polygon, LDObject* polygonOwner, VboSubclass subclass) const -{ - QColor color; - - switch (subclass) - { - case VboSubclass::Surfaces: - case VboSubclass::Normals: - case VboSubclass::_End: - // Surface and normal VBOs contain vertex data, not colors. So we can't return anything meaningful. - return {}; - - case VboSubclass::BfcFrontColors: - // Use the constant green color for BFC front colors - return {64, 192, 80}; - - case VboSubclass::BfcBackColors: - // Use the constant red color for BFC back colors - return {208, 64, 64}; - - case VboSubclass::PickColors: - // For the picking scene, determine the color from the owner's ID. - return indexColorForID(polygonOwner->id()); - - case VboSubclass::RandomColors: - // For the random color scene, the owner object has rolled up a random color. Use that. - color = polygonOwner->randomColor(); - break; - - case VboSubclass::NormalColors: - // For normal colors, use the polygon's color. - if (polygon.color == MainColor) - { - // If it's the main color, use the polygon owner's color. - if (polygonOwner->color() == MainColor) - { - // If that also is the main color, then we whatever the user has configured the main color to look like. - color = guiUtilities()->mainColorRepresentation(); - } - else - { - color = polygonOwner->color().faceColor(); - } - } - else if (polygon.color == EdgeColor) - { - // Edge color is black, unless we have a dark background, in which case lines need to be bright. - color = luma(m_config->backgroundColor()) > 40 ? Qt::black : Qt::white; - } - else - { - // Not main or edge color, use the polygon's color as is. - color = LDColor {polygon.color}.faceColor(); - } - break; - } - - if (color.isValid()) - { - // We may wish to apply blending on the color to indicate selection or highlight. - double blendAlpha = 0.0; - - if (polygonOwner->isSelected()) - blendAlpha = 1.0; - else if (polygonOwner == m_renderer->objectAtCursor()) - blendAlpha = 0.5; - - if (blendAlpha != 0.0) - { - QColor selectedColor = m_config->selectColorBlend(); - double denominator = blendAlpha + 1.0; - color.setRed((color.red() + (selectedColor.red() * blendAlpha)) / denominator); - color.setGreen((color.green() + (selectedColor.green() * blendAlpha)) / denominator); - color.setBlue((color.blue() + (selectedColor.blue() * blendAlpha)) / denominator); - } - } - else - { - // The color was unknown. Use main color to make the polygon at least not appear pitch-black. - if (polygon.num != 2 and polygon.num != 5) - color = guiUtilities()->mainColorRepresentation(); - else - color = Qt::black; - - // Warn about the unknown color, but only once. - static QSet<int> warnedColors; - if (not warnedColors.contains(polygon.color)) - { - print("Unknown color %1!\n", polygon.color); - warnedColors.insert(polygon.color); - } - } - - return color; -} - - -void GLCompiler::needMerge() -{ - for (int i = 0; i < countof (m_vboChanged); ++i) - m_vboChanged[i] = true; -} - - -void GLCompiler::stageForCompilation (LDObject* obj) -{ - m_staged << obj; -} - - -void GLCompiler::unstage (LDObject* obj) -{ - m_staged.remove (obj); -} - - -void GLCompiler::compileStaged() -{ - for (LDObject* object : m_staged) - compileObject(object); - - m_staged.clear(); -} - - -void GLCompiler::prepareVBO (int vbonum, const Model* model) -{ - // Compile anything that still awaits it - compileStaged(); - - if (not m_vboChanged[vbonum]) - return; - - QVector<GLfloat> vbodata; - - for (auto it = m_objectInfo.begin(); it != m_objectInfo.end();) - { - if (it.key() == nullptr) - { - it = m_objectInfo.erase (it); - continue; - } - - if (it.key()->model() == model and not it.key()->isHidden()) - vbodata += it->data[vbonum]; - - ++it; - } - - glBindBuffer (GL_ARRAY_BUFFER, m_vbo[vbonum]); - glBufferData (GL_ARRAY_BUFFER, countof(vbodata) * sizeof(GLfloat), vbodata.constData(), GL_STATIC_DRAW); - glBindBuffer (GL_ARRAY_BUFFER, 0); - CHECK_GL_ERROR(); - m_vboChanged[vbonum] = false; - m_vboSizes[vbonum] = countof(vbodata); -} - - -void GLCompiler::dropObjectInfo(LDObject* object) -{ - if (m_objectInfo.contains(object)) - { - m_objectInfo.remove(object); - needMerge(); - } -} - -void GLCompiler::forgetObject(LDObject* object) -{ - dropObjectInfo(object); - m_staged.remove(object); -} - - -void GLCompiler::compileObject (LDObject* obj) -{ - if (obj == nullptr) - return; - - ObjectVBOInfo info; - info.isChanged = true; - dropObjectInfo (obj); - - switch (obj->type()) - { - // Note: We cannot split quads into triangles here, it would mess up the wireframe view. - // Quads must go into separate vbos. - case LDObjectType::Triangle: - case LDObjectType::Quadrilateral: - case LDObjectType::EdgeLine: - case LDObjectType::ConditionalEdge: - { - LDPolygon* poly = obj->getPolygon(); - poly->id = obj->id(); - compilePolygon (*poly, obj, &info); - delete poly; - break; - } - - case LDObjectType::SubfileReference: - { - LDSubfileReference* ref = static_cast<LDSubfileReference*> (obj); - auto data = ref->inlinePolygons(); - - for (LDPolygon& poly : data) - { - poly.id = obj->id(); - compilePolygon (poly, obj, &info); - } - break; - } - - case LDObjectType::BezierCurve: - { - LDBezierCurve* curve = static_cast<LDBezierCurve*> (obj); - for (LDPolygon& polygon : curve->rasterizePolygons(grid()->bezierCurveSegments())) - { - polygon.id = obj->id(); - compilePolygon (polygon, obj, &info); - } - } - break; - - default: - break; - } - - m_objectInfo[obj] = info; - needMerge(); -} - - -void GLCompiler::compilePolygon (LDPolygon& poly, LDObject* topobj, ObjectVBOInfo* objinfo) -{ - VboClass surface; - int vertexCount; - - switch (poly.num) - { - case 2: surface = VboClass::Lines; vertexCount = 2; break; - case 3: surface = VboClass::Triangles; vertexCount = 3; break; - case 4: surface = VboClass::Quads; vertexCount = 4; break; - case 5: surface = VboClass::ConditionalLines; vertexCount = 2; break; - default: return; - } - - // Determine the normals for the polygon. - Vertex normals[4]; - auto vertexRing = ring(poly.vertices, vertexCount); - - for (int i = 0; i < vertexCount; ++i) - { - const Vertex& v1 = vertexRing[i - 1]; - const Vertex& v2 = vertexRing[i]; - const Vertex& v3 = vertexRing[i + 1]; - normals[i] = Vertex::crossProduct(v3 - v2, v1 - v2).normalized(); - } - - for (VboSubclass complement : iterateEnum<VboSubclass>()) - { - const int vbonum = vboNumber (surface, complement); - QVector<GLfloat>& vbodata = objinfo->data[vbonum]; - const QColor color = getColorForPolygon (poly, topobj, complement); - - for (int vert = 0; vert < vertexCount; ++vert) - { - if (complement == VboSubclass::Surfaces) - { - // Write coordinates. Apparently Z must be flipped too? - vbodata << poly.vertices[vert].x() - << -poly.vertices[vert].y() - << -poly.vertices[vert].z(); - } - else if (complement == VboSubclass::Normals) - { - vbodata << normals[vert].x() - << -normals[vert].y() - << -normals[vert].z(); - } - else - { - vbodata << ((GLfloat) color.red()) / 255.0f - << ((GLfloat) color.green()) / 255.0f - << ((GLfloat) color.blue()) / 255.0f - << ((GLfloat) color.alpha()) / 255.0f; - } - } - } -} - - -void GLCompiler::setRenderer (GLRenderer* renderer) -{ - m_renderer = renderer; -} - - -int GLCompiler::vboNumber (VboClass surface, VboSubclass complement) -{ - return (static_cast<int>(surface) * EnumLimits<VboSubclass>::Count) + static_cast<int>(complement); -} - - -GLuint GLCompiler::vbo (int vbonum) const -{ - return m_vbo[vbonum]; -} - - -int GLCompiler::vboSize (int vbonum) const -{ - return m_vboSizes[vbonum]; -} - - -void GLCompiler::recompile() -{ - for (LDObject* object : m_renderer->model()->objects()) - compileObject(object); -}
--- a/src/glCompiler.h Tue Feb 14 14:52:01 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* - * LDForge: LDraw parts authoring CAD - * Copyright (C) 2013 - 2017 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/>. - */ - -#pragma once -#include "main.h" -#include "glrenderer.h" -#include "glShared.h" -#include <QMap> -#include <QSet> - -// ============================================================================= -// -class GLCompiler : public QObject, public HierarchyElement, protected QOpenGLFunctions -{ - Q_OBJECT - -public: - struct ObjectVBOInfo - { - QVector<GLfloat> data[NumVbos]; - bool isChanged; - }; - - GLCompiler (GLRenderer* renderer); - ~GLCompiler(); - QColor getColorForPolygon (LDPolygon& poly, LDObject* topobj, VboSubclass complement) const; - QColor indexColorForID (int id) const; - void initialize(); - void needMerge(); - void prepareVBO (int vbonum, const Model* model); - void setRenderer (GLRenderer* compiler); - void stageForCompilation (LDObject* obj); - void unstage (LDObject* obj); - GLuint vbo (int vbonum) const; - int vboSize (int vbonum) const; - - static int vboNumber (VboClass surface, VboSubclass complement); - -private: - void compileStaged(); - void compilePolygon (LDPolygon& poly, LDObject* topobj, ObjectVBOInfo* objinfo); - Q_SLOT void compileObject (LDObject* obj); - Q_SLOT void recompile(); - void dropObjectInfo (LDObject* obj); - Q_SLOT void forgetObject(LDObject* object); - -private: - QMap<LDObject*, ObjectVBOInfo> m_objectInfo; - QSet<LDObject*> m_staged; // Objects that need to be compiled - GLuint m_vbo[NumVbos]; - bool m_vboChanged[NumVbos] = {true}; - int m_vboSizes[NumVbos] = {0}; - GLRenderer* m_renderer; -}; - -#define CHECK_GL_ERROR() { CheckGLErrorImpl (__FILE__, __LINE__); } -void CheckGLErrorImpl (const char* file, int line);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/glcompiler.cpp Tue Feb 14 14:53:06 2017 +0200 @@ -0,0 +1,432 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013 - 2017 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/>. + */ + +#define GL_GLEXT_PROTOTYPES +#include <GL/glu.h> +#include <GL/glext.h> +#include "glcompiler.h" +#include "miscallenous.h" +#include "guiutilities.h" +#include "documentmanager.h" +#include "grid.h" + +struct GLErrorInfo +{ + GLenum value; + QString text; +}; + +static const GLErrorInfo g_GLErrors[] = +{ + { GL_NO_ERROR, "No error" }, + { GL_INVALID_ENUM, "Unacceptable enumerator passed" }, + { GL_INVALID_VALUE, "Numeric argument out of range" }, + { GL_INVALID_OPERATION, "The operation is not allowed to be done in this state" }, + { GL_INVALID_FRAMEBUFFER_OPERATION, "Framebuffer object is not complete"}, + { GL_OUT_OF_MEMORY, "Out of memory" }, + { GL_STACK_UNDERFLOW, "The operation would have caused an underflow" }, + { GL_STACK_OVERFLOW, "The operation would have caused an overflow" }, +}; + +void CheckGLErrorImpl (const char* file, int line) +{ + QString errmsg; + GLenum errnum = glGetError(); + + if (errnum == GL_NO_ERROR) + return; + + for (const GLErrorInfo& err : g_GLErrors) + { + if (err.value == errnum) + { + errmsg = err.text; + break; + } + } + + print ("OpenGL ERROR: at %1:%2: %3", Basename (QString (file)), line, errmsg); +} + + +GLCompiler::GLCompiler (GLRenderer* renderer) : + HierarchyElement (renderer), + m_renderer (renderer) +{ + connect(renderer->model(), SIGNAL(objectAdded(LDObject*)), this, SLOT(compileObject(LDObject*))); + connect(renderer->model(), SIGNAL(objectModified(LDObject*)), this, SLOT(compileObject(LDObject*))); + connect(renderer->model(), SIGNAL(aboutToRemoveObject(LDObject*)), this, SLOT(forgetObject(LDObject*)), Qt::DirectConnection); + connect(renderer, SIGNAL(objectHighlightingChanged(LDObject*)), this, SLOT(compileObject(LDObject*))); + connect(m_window, SIGNAL(gridChanged()), this, SLOT(recompile())); + + for (LDObject* object : renderer->model()->objects()) + stageForCompilation(object); +} + + +void GLCompiler::initialize() +{ + initializeOpenGLFunctions(); + glGenBuffers (NumVbos, &m_vbo[0]); + CHECK_GL_ERROR(); +} + + +GLCompiler::~GLCompiler() +{ + glDeleteBuffers (NumVbos, &m_vbo[0]); + CHECK_GL_ERROR(); +} + + +QColor GLCompiler::indexColorForID (int id) const +{ + // Calculate a color based from this index. This method caters for + // 16777216 objects. I don't think that will be exceeded anytime soon. :) + int r = (id / 0x10000) % 0x100; + int g = (id / 0x100) % 0x100; + int b = id % 0x100; + return {r, g, b}; +} + +/* + * Returns the suitable color for the polygon. + * - polygon is the polygon to colorise. + * - polygonOwner is the LDObject from which the polygon originated. + * - subclass provides context for the polygon. + */ +QColor GLCompiler::getColorForPolygon(LDPolygon& polygon, LDObject* polygonOwner, VboSubclass subclass) const +{ + QColor color; + + switch (subclass) + { + case VboSubclass::Surfaces: + case VboSubclass::Normals: + case VboSubclass::_End: + // Surface and normal VBOs contain vertex data, not colors. So we can't return anything meaningful. + return {}; + + case VboSubclass::BfcFrontColors: + // Use the constant green color for BFC front colors + return {64, 192, 80}; + + case VboSubclass::BfcBackColors: + // Use the constant red color for BFC back colors + return {208, 64, 64}; + + case VboSubclass::PickColors: + // For the picking scene, determine the color from the owner's ID. + return indexColorForID(polygonOwner->id()); + + case VboSubclass::RandomColors: + // For the random color scene, the owner object has rolled up a random color. Use that. + color = polygonOwner->randomColor(); + break; + + case VboSubclass::NormalColors: + // For normal colors, use the polygon's color. + if (polygon.color == MainColor) + { + // If it's the main color, use the polygon owner's color. + if (polygonOwner->color() == MainColor) + { + // If that also is the main color, then we whatever the user has configured the main color to look like. + color = guiUtilities()->mainColorRepresentation(); + } + else + { + color = polygonOwner->color().faceColor(); + } + } + else if (polygon.color == EdgeColor) + { + // Edge color is black, unless we have a dark background, in which case lines need to be bright. + color = luma(m_config->backgroundColor()) > 40 ? Qt::black : Qt::white; + } + else + { + // Not main or edge color, use the polygon's color as is. + color = LDColor {polygon.color}.faceColor(); + } + break; + } + + if (color.isValid()) + { + // We may wish to apply blending on the color to indicate selection or highlight. + double blendAlpha = 0.0; + + if (polygonOwner->isSelected()) + blendAlpha = 1.0; + else if (polygonOwner == m_renderer->objectAtCursor()) + blendAlpha = 0.5; + + if (blendAlpha != 0.0) + { + QColor selectedColor = m_config->selectColorBlend(); + double denominator = blendAlpha + 1.0; + color.setRed((color.red() + (selectedColor.red() * blendAlpha)) / denominator); + color.setGreen((color.green() + (selectedColor.green() * blendAlpha)) / denominator); + color.setBlue((color.blue() + (selectedColor.blue() * blendAlpha)) / denominator); + } + } + else + { + // The color was unknown. Use main color to make the polygon at least not appear pitch-black. + if (polygon.num != 2 and polygon.num != 5) + color = guiUtilities()->mainColorRepresentation(); + else + color = Qt::black; + + // Warn about the unknown color, but only once. + static QSet<int> warnedColors; + if (not warnedColors.contains(polygon.color)) + { + print("Unknown color %1!\n", polygon.color); + warnedColors.insert(polygon.color); + } + } + + return color; +} + + +void GLCompiler::needMerge() +{ + for (int i = 0; i < countof (m_vboChanged); ++i) + m_vboChanged[i] = true; +} + + +void GLCompiler::stageForCompilation (LDObject* obj) +{ + m_staged << obj; +} + + +void GLCompiler::unstage (LDObject* obj) +{ + m_staged.remove (obj); +} + + +void GLCompiler::compileStaged() +{ + for (LDObject* object : m_staged) + compileObject(object); + + m_staged.clear(); +} + + +void GLCompiler::prepareVBO (int vbonum, const Model* model) +{ + // Compile anything that still awaits it + compileStaged(); + + if (not m_vboChanged[vbonum]) + return; + + QVector<GLfloat> vbodata; + + for (auto it = m_objectInfo.begin(); it != m_objectInfo.end();) + { + if (it.key() == nullptr) + { + it = m_objectInfo.erase (it); + continue; + } + + if (it.key()->model() == model and not it.key()->isHidden()) + vbodata += it->data[vbonum]; + + ++it; + } + + glBindBuffer (GL_ARRAY_BUFFER, m_vbo[vbonum]); + glBufferData (GL_ARRAY_BUFFER, countof(vbodata) * sizeof(GLfloat), vbodata.constData(), GL_STATIC_DRAW); + glBindBuffer (GL_ARRAY_BUFFER, 0); + CHECK_GL_ERROR(); + m_vboChanged[vbonum] = false; + m_vboSizes[vbonum] = countof(vbodata); +} + + +void GLCompiler::dropObjectInfo(LDObject* object) +{ + if (m_objectInfo.contains(object)) + { + m_objectInfo.remove(object); + needMerge(); + } +} + +void GLCompiler::forgetObject(LDObject* object) +{ + dropObjectInfo(object); + m_staged.remove(object); +} + + +void GLCompiler::compileObject (LDObject* obj) +{ + if (obj == nullptr) + return; + + ObjectVBOInfo info; + info.isChanged = true; + dropObjectInfo (obj); + + switch (obj->type()) + { + // Note: We cannot split quads into triangles here, it would mess up the wireframe view. + // Quads must go into separate vbos. + case LDObjectType::Triangle: + case LDObjectType::Quadrilateral: + case LDObjectType::EdgeLine: + case LDObjectType::ConditionalEdge: + { + LDPolygon* poly = obj->getPolygon(); + poly->id = obj->id(); + compilePolygon (*poly, obj, &info); + delete poly; + break; + } + + case LDObjectType::SubfileReference: + { + LDSubfileReference* ref = static_cast<LDSubfileReference*> (obj); + auto data = ref->inlinePolygons(); + + for (LDPolygon& poly : data) + { + poly.id = obj->id(); + compilePolygon (poly, obj, &info); + } + break; + } + + case LDObjectType::BezierCurve: + { + LDBezierCurve* curve = static_cast<LDBezierCurve*> (obj); + for (LDPolygon& polygon : curve->rasterizePolygons(grid()->bezierCurveSegments())) + { + polygon.id = obj->id(); + compilePolygon (polygon, obj, &info); + } + } + break; + + default: + break; + } + + m_objectInfo[obj] = info; + needMerge(); +} + + +void GLCompiler::compilePolygon (LDPolygon& poly, LDObject* topobj, ObjectVBOInfo* objinfo) +{ + VboClass surface; + int vertexCount; + + switch (poly.num) + { + case 2: surface = VboClass::Lines; vertexCount = 2; break; + case 3: surface = VboClass::Triangles; vertexCount = 3; break; + case 4: surface = VboClass::Quads; vertexCount = 4; break; + case 5: surface = VboClass::ConditionalLines; vertexCount = 2; break; + default: return; + } + + // Determine the normals for the polygon. + Vertex normals[4]; + auto vertexRing = ring(poly.vertices, vertexCount); + + for (int i = 0; i < vertexCount; ++i) + { + const Vertex& v1 = vertexRing[i - 1]; + const Vertex& v2 = vertexRing[i]; + const Vertex& v3 = vertexRing[i + 1]; + normals[i] = Vertex::crossProduct(v3 - v2, v1 - v2).normalized(); + } + + for (VboSubclass complement : iterateEnum<VboSubclass>()) + { + const int vbonum = vboNumber (surface, complement); + QVector<GLfloat>& vbodata = objinfo->data[vbonum]; + const QColor color = getColorForPolygon (poly, topobj, complement); + + for (int vert = 0; vert < vertexCount; ++vert) + { + if (complement == VboSubclass::Surfaces) + { + // Write coordinates. Apparently Z must be flipped too? + vbodata << poly.vertices[vert].x() + << -poly.vertices[vert].y() + << -poly.vertices[vert].z(); + } + else if (complement == VboSubclass::Normals) + { + vbodata << normals[vert].x() + << -normals[vert].y() + << -normals[vert].z(); + } + else + { + vbodata << ((GLfloat) color.red()) / 255.0f + << ((GLfloat) color.green()) / 255.0f + << ((GLfloat) color.blue()) / 255.0f + << ((GLfloat) color.alpha()) / 255.0f; + } + } + } +} + + +void GLCompiler::setRenderer (GLRenderer* renderer) +{ + m_renderer = renderer; +} + + +int GLCompiler::vboNumber (VboClass surface, VboSubclass complement) +{ + return (static_cast<int>(surface) * EnumLimits<VboSubclass>::Count) + static_cast<int>(complement); +} + + +GLuint GLCompiler::vbo (int vbonum) const +{ + return m_vbo[vbonum]; +} + + +int GLCompiler::vboSize (int vbonum) const +{ + return m_vboSizes[vbonum]; +} + + +void GLCompiler::recompile() +{ + for (LDObject* object : m_renderer->model()->objects()) + compileObject(object); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/glcompiler.h Tue Feb 14 14:53:06 2017 +0200 @@ -0,0 +1,72 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013 - 2017 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/>. + */ + +#pragma once +#include "main.h" +#include "glrenderer.h" +#include "glShared.h" +#include <QMap> +#include <QSet> + +// ============================================================================= +// +class GLCompiler : public QObject, public HierarchyElement, protected QOpenGLFunctions +{ + Q_OBJECT + +public: + struct ObjectVBOInfo + { + QVector<GLfloat> data[NumVbos]; + bool isChanged; + }; + + GLCompiler (GLRenderer* renderer); + ~GLCompiler(); + QColor getColorForPolygon (LDPolygon& poly, LDObject* topobj, VboSubclass complement) const; + QColor indexColorForID (int id) const; + void initialize(); + void needMerge(); + void prepareVBO (int vbonum, const Model* model); + void setRenderer (GLRenderer* compiler); + void stageForCompilation (LDObject* obj); + void unstage (LDObject* obj); + GLuint vbo (int vbonum) const; + int vboSize (int vbonum) const; + + static int vboNumber (VboClass surface, VboSubclass complement); + +private: + void compileStaged(); + void compilePolygon (LDPolygon& poly, LDObject* topobj, ObjectVBOInfo* objinfo); + Q_SLOT void compileObject (LDObject* obj); + Q_SLOT void recompile(); + void dropObjectInfo (LDObject* obj); + Q_SLOT void forgetObject(LDObject* object); + +private: + QMap<LDObject*, ObjectVBOInfo> m_objectInfo; + QSet<LDObject*> m_staged; // Objects that need to be compiled + GLuint m_vbo[NumVbos]; + bool m_vboChanged[NumVbos] = {true}; + int m_vboSizes[NumVbos] = {0}; + GLRenderer* m_renderer; +}; + +#define CHECK_GL_ERROR() { CheckGLErrorImpl (__FILE__, __LINE__); } +void CheckGLErrorImpl (const char* file, int line);
--- a/src/glrenderer.cpp Tue Feb 14 14:52:01 2017 +0200 +++ b/src/glrenderer.cpp Tue Feb 14 14:53:06 2017 +0200 @@ -30,7 +30,7 @@ #include "mainwindow.h" #include "miscallenous.h" #include "editHistory.h" -#include "glCompiler.h" +#include "glcompiler.h" #include "primitives.h" #include "documentmanager.h" #include "grid.h"
--- a/src/ldObject.cpp Tue Feb 14 14:52:01 2017 +0200 +++ b/src/ldObject.cpp Tue Feb 14 14:53:06 2017 +0200 @@ -25,7 +25,7 @@ #include "editHistory.h" #include "canvas.h" #include "colors.h" -#include "glCompiler.h" +#include "glcompiler.h" #include "linetypes/edgeline.h" // List of all LDObjects
--- a/src/mainwindow.cpp Tue Feb 14 14:52:01 2017 +0200 +++ b/src/mainwindow.cpp Tue Feb 14 14:53:06 2017 +0200 @@ -35,7 +35,7 @@ #include "dialogs/configdialog.h" #include "linetypes/comment.h" #include "guiutilities.h" -#include "glCompiler.h" +#include "glcompiler.h" #include "documentmanager.h" #include "ldobjectiterator.h" #include "grid.h"
--- a/src/toolsets/viewtoolset.cpp Tue Feb 14 14:52:01 2017 +0200 +++ b/src/toolsets/viewtoolset.cpp Tue Feb 14 14:53:06 2017 +0200 @@ -24,7 +24,7 @@ #include "../canvas.h" #include "../primitives.h" #include "../colors.h" -#include "../glCompiler.h" +#include "../glcompiler.h" #include "../documentmanager.h" #include "viewtoolset.h"