# HG changeset patch # User Teemu Piippo # Date 1577893556 -7200 # Node ID 0133e565e0729bd95a47938e8ce1e05f6222728e # Parent cef43609a374904f7c81a20b4fa4d9383ee0d883 things diff -r cef43609a374 -r 0133e565e072 CMakeLists.txt --- a/CMakeLists.txt Sat Dec 14 23:00:01 2019 +0200 +++ b/CMakeLists.txt Wed Jan 01 17:45:56 2020 +0200 @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 2.8.12) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMake") include(cotire) +set(OpenGL_GL_PREFERENCE GLVND) find_package(Qt5Widgets REQUIRED) if (Qt5Widgets_VERSION VERSION_LESS 5.5.0) message(FATAL_ERROR "Qt5 version 5.5 required") @@ -51,6 +52,7 @@ src/colors.h src/document.h src/documentmanager.h + src/header.h src/invert.h src/libraries.h src/main.h diff -r cef43609a374 -r 0133e565e072 src/basics.h --- a/src/basics.h Sat Dec 14 23:00:01 2019 +0200 +++ b/src/basics.h Wed Jan 01 17:45:56 2020 +0200 @@ -36,9 +36,9 @@ enum Axis { - X, - Y, - Z + X = 0, + Y = 1, + Z = 2 }; enum Winding @@ -65,3 +65,9 @@ one = one ^ other; return one; } + +template +constexpr int countof(T(&)[N]) +{ + return N; +} diff -r cef43609a374 -r 0133e565e072 src/colors.h --- a/src/colors.h Sat Dec 14 23:00:01 2019 +0200 +++ b/src/colors.h Wed Jan 01 17:45:56 2020 +0200 @@ -6,6 +6,36 @@ qint32 index; }; +inline bool operator==(const Color& one, const Color& other) +{ + return one.index == other.index; +} + +inline bool operator!=(const Color& one, const Color& other) +{ + return one.index != other.index; +} + +inline bool operator<(const Color& one, const Color& other) +{ + return one.index < other.index; +} + +inline bool operator<=(const Color& one, const Color& other) +{ + return one.index <= other.index; +} + +inline bool operator>(const Color& one, const Color& other) +{ + return one.index > other.index; +} + +inline bool operator>=(const Color& one, const Color& other) +{ + return one.index >= other.index; +} + namespace colors { static constexpr Color black {0}; diff -r cef43609a374 -r 0133e565e072 src/document.cpp --- a/src/document.cpp Sat Dec 14 23:00:01 2019 +0200 +++ b/src/document.cpp Wed Jan 01 17:45:56 2020 +0200 @@ -2,13 +2,18 @@ #include "ui_document.h" #include "model.h" -Document::Document(Model* model, QWidget* parent) : +Document::Document(Model* model, DocumentManager* documents, QWidget* parent) : QWidget{parent}, model{model}, + documents{documents}, + renderer{new PartRenderer{model, documents, this}}, ui{*new Ui::Document} { this->ui.setupUi(this); this->ui.listView->setModel(model); + QVBoxLayout* layout = new QVBoxLayout; + layout->addWidget(this->renderer); + this->ui.viewportFrame->setLayout(layout); connect(this->ui.splitter, &QSplitter::splitterMoved, this, &Document::splitterChanged); } diff -r cef43609a374 -r 0133e565e072 src/document.h --- a/src/document.h Sat Dec 14 23:00:01 2019 +0200 +++ b/src/document.h Wed Jan 01 17:45:56 2020 +0200 @@ -1,6 +1,7 @@ #pragma once #include #include +#include "gl/partrenderer.h" namespace Ui { @@ -13,7 +14,7 @@ { Q_OBJECT public: - explicit Document(Model* model, QWidget *parent = nullptr); + explicit Document(Model* model, DocumentManager* documents, QWidget *parent = nullptr); ~Document(); QByteArray saveSplitterState() const; void restoreSplitterState(const QByteArray& state); @@ -21,5 +22,7 @@ void splitterChanged(); private: Model* model; + DocumentManager* const documents; + PartRenderer* renderer; Ui::Document& ui; }; diff -r cef43609a374 -r 0133e565e072 src/document.ui --- a/src/document.ui Sat Dec 14 23:00:01 2019 +0200 +++ b/src/document.ui Wed Jan 01 17:45:56 2020 +0200 @@ -19,19 +19,19 @@ Qt::Horizontal - + + + QFrame::StyledPanel + + + QFrame::Raised + + - - - PartRenderer - QOpenGLWidget -
gl/partrenderer.h
-
-
diff -r cef43609a374 -r 0133e565e072 src/documentmanager.h --- a/src/documentmanager.h Sat Dec 14 23:00:01 2019 +0200 +++ b/src/documentmanager.h Wed Jan 01 17:45:56 2020 +0200 @@ -7,11 +7,7 @@ Q_OBJECT using ModelPointer = std::unique_ptr; public: - DocumentManager(QObject* parent = nullptr); - DocumentManager(const DocumentManager&) = delete; - DocumentManager(DocumentManager&&) = default; - DocumentManager& operator=(const DocumentManager&) = delete; - DocumentManager& operator=(DocumentManager&&) = default; + DocumentManager(QObject* parent = nullptr); QString newModel(); Model* findModelByName(const QString& name); QString openModel(const QString& path, QTextStream& errorStream); diff -r cef43609a374 -r 0133e565e072 src/gl/common.h --- a/src/gl/common.h Sat Dec 14 23:00:01 2019 +0200 +++ b/src/gl/common.h Wed Jan 01 17:45:56 2020 +0200 @@ -55,6 +55,7 @@ Type type; Point3D vertices[4]; Color color; + linetypes::Id id; /** * @return amount of vertices used for geometry @@ -91,14 +92,19 @@ namespace gl { - inline Polygon edgeLine(const Point3D& v_1, const Point3D& v_2, Color color) + inline Polygon edgeLine(const Point3D& v_1, const Point3D& v_2, Color color, linetypes::Id id) { - return {Polygon::EdgeLine, {v_1, v_2}, color}; + return {Polygon::EdgeLine, {v_1, v_2}, color, id}; } - inline Polygon triangle(const Point3D& v_1, const Point3D& v_2, const Point3D& v_3, Color color) + inline Polygon triangle( + const Point3D& v_1, + const Point3D& v_2, + const Point3D& v_3, + Color color, + linetypes::Id id) { - return {Polygon::Triangle, {v_1, v_2, v_3}, color}; + return {Polygon::Triangle, {v_1, v_2, v_3}, color, id}; } inline Polygon quadrilateral( @@ -106,9 +112,10 @@ const Point3D& v_2, const Point3D& v_3, const Point3D& v_4, - Color color) + Color color, + linetypes::Id id) { - return {Polygon::Quadrilateral, {v_1, v_2, v_3, v_4}, color}; + return {Polygon::Quadrilateral, {v_1, v_2, v_3, v_4}, color, id}; } inline Polygon conditionalEdge( @@ -116,13 +123,14 @@ const Point3D& v_2, const Point3D& control_1, const Point3D& control_2, - Color color) + Color color, + linetypes::Id id) { - return {Polygon::ConditionalEdge, {v_1, v_2, control_1, control_2}, color}; + return {Polygon::ConditionalEdge, {v_1, v_2, control_1, control_2}, color, id}; } // Vbo names - enum class VboClass + enum class VboClass : std::uint8_t { Lines, Triangles, @@ -132,7 +140,7 @@ constexpr int numVboClasses = 4; // Types of vbo per object - enum class VboSubclass + enum class VboSubclass : std::uint8_t { Surfaces, RegularColors, diff -r cef43609a374 -r 0133e565e072 src/gl/compiler.cpp --- a/src/gl/compiler.cpp Sat Dec 14 23:00:01 2019 +0200 +++ b/src/gl/compiler.cpp Wed Jan 01 17:45:56 2020 +0200 @@ -24,7 +24,222 @@ #include "invert.h" #include "ring.h" +gl::Compiler::Compiler(QObject* parent) : + QObject{parent} +{ +} + gl::Compiler::~Compiler() { } + +void gl::Compiler::build(Model* model, DocumentManager* context) +{ + if (not this->initialized) + { + this->initializeVbo(); + } + std::vector vboData[gl::numVbos]; + const std::vector polygons = model->getPolygons(context); + for (const gl::Polygon& polygon : polygons) + { + this->buildPolygon(polygon, vboData); + } + for (int i = 0; i < gl::numVbos; i += 1) + { + this->upload(i, vboData[i]); + } +} + +gl::VboClass classifyPolygon(const gl::Polygon& polygon) +{ + switch (polygon.type) + { + case gl::Polygon::EdgeLine: + return gl::VboClass::Lines; + case gl::Polygon::Triangle: + return gl::VboClass::Triangles; + case gl::Polygon::Quadrilateral: + return gl::VboClass::Quads; + case gl::Polygon::ConditionalEdge: + return gl::VboClass::ConditionalLines; + } + return gl::VboClass::Lines; +} + +QColor colorFromId(linetypes::Id id) +{ + // Calculate a color based from this index. This method caters for + // 16777216 objects. I don't think that will be exceeded anytime soon. + const int r = (id.value / 0x10000) % 0x100; + const int g = (id.value / 0x100) % 0x100; + const int b = id.value % 0x100; + return {r, g, b}; +} + +void writeVertex(std::vector& data, const Point3D& point) +{ + data.push_back(point.x); + data.push_back(point.y); + data.push_back(point.z); +} + +void gl::Compiler::buildPolygon(gl::Polygon polygon, std::vector* vboData) +{ + const gl::VboClass vboClass = classifyPolygon(polygon); + auto vboBuffer = [&](VboSubclass subclass) -> std::vector& + { + return vboData[gl::vboIndex({vboClass, subclass})]; + }; + auto vertexRing = iter::ring(polygon.vertices, polygon.numPolygonVertices()); + for (int i = 0; i < polygon.numPolygonVertices(); i += 1) + { + const Point3D& v1 = vertexRing[i - 1]; + const Point3D& v2 = vertexRing[i]; + const Point3D& v3 = vertexRing[i + 1]; + const QVector3D normal = QVector3D::crossProduct(v3 - v2, v1 - v2).normalized(); + std::vector& data = vboBuffer(VboSubclass::Normals); + for (const GLfloat coord : {normal.x(), normal.y(), normal.z()}) + data.push_back(coord); + } + vboBuffer(VboSubclass::Surfaces).reserve(vboBuffer(VboSubclass::Surfaces).size() + polygon.numPolygonVertices()); + // Transform vertices so that they're suitable for GL rendering + for (int i = 0; i < polygon.numPolygonVertices(); i += 1) + { + polygon.vertices[i].y = -polygon.vertices[i].y; + polygon.vertices[i].z = -polygon.vertices[i].z; +#if 0 + // Add these vertices to the bounding box (unless we're going to do it over + // from scratch afterwards anyway) + if (not this->needBoundingBoxRebuild) + { + this->boundingBox.consider(poly.vertices[i]); + } +#endif + writeVertex(vboBuffer(VboSubclass::Surfaces), polygon.vertices[i]); + } + this->writeColor(vboData, polygon, VboSubclass::RegularColors); + this->writeColor(vboData, polygon, VboSubclass::PickColors); + this->writeColor(vboData, polygon, VboSubclass::BfcFrontColors); + this->writeColor(vboData, polygon, VboSubclass::BfcBackColors); +} + +QColor gl::Compiler::getColorForPolygon(const gl::Polygon& polygon, VboSubclass subclass) +{ + QColor color; + + switch (subclass) + { + case VboSubclass::Surfaces: + case VboSubclass::Normals: + case VboSubclass::InvertedNormals: + // 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, use unique picking colors provided by the model. + return colorFromId(polygon.id); + case VboSubclass::RandomColors: + // For the random color scene, the owner object has rolled up a random color. Use that. + color = {255, 64, 255}; // polygonOwner->randomColor(); + break; + case VboSubclass::RegularColors: + // For normal colors, use the polygon's color. + if (polygon.color == colors::main) + { + color = {255, 255, 64}; // mainColorRepresentation(); + } + else if (polygon.color == colors::edge) + { + // Edge color is black, unless we have a dark background, in which case lines need to be bright. + color = Qt::black; //luma(config::backgroundColor()) > 40 ? Qt::black : Qt::white; + } + else + { + // Not main or edge color, use the polygon's color as is. + color = {255, 255, 64}; //polygon.color.faceColor(); + } + break; + } + + if (color.isValid()) + { + // We may wish to apply blending on the color to indicate selection or highlight. + /* + const double blendAlpha = 0.0; + if (blendAlpha != 0.0) + { + QColor selectedColor = 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 + { + if (polygon.numPolygonVertices() == 2) + color = Qt::black; + else + color = {255, 255, 64}; + } + + return color; +} + +void gl::Compiler::writeColor(std::vector* data, const gl::Polygon& polygon, VboSubclass subclass) +{ + std::vector& buffer = data[gl::vboIndex({classifyPolygon(polygon), subclass})]; + const QColor color = this->getColorForPolygon(polygon, subclass); + buffer.reserve(data->size() + 4 * polygon.numPolygonVertices()); + for (int i = 0; i < polygon.numPolygonVertices(); i += 1) + { + buffer.push_back(color.redF() / 255.0f); + buffer.push_back(color.greenF() / 255.0f); + buffer.push_back(color.blueF() / 255.0f); + buffer.push_back(color.alphaF() / 255.0f); + } +} + +void gl::Compiler::initializeVbo() +{ + this->initializeOpenGLFunctions(); + glGenBuffers(countof(this->storedVbo), &this->storedVbo[0]); + this->initialized = true; +} + +/// +/// \brief Uploads data to a vbo +/// \param vboAddress Which vbo to upload to +/// \param data Data to upload to vbo +/// +void gl::Compiler::upload(const int vboIndex, const std::vector& data) +{ + glBindBuffer(GL_ARRAY_BUFFER, this->storedVbo[vboIndex]); + glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof data[0], data.data(), GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + this->storedVboSizes[vboIndex] = data.size(); +} + +GLuint gl::Compiler::vbo(const VboAddress vboAddress) const +{ + return this->storedVbo[gl::vboIndex(vboAddress)]; +} + +int gl::Compiler::vboSize(const VboAddress vboAddress) const +{ + return this->storedVboSizes[gl::vboIndex(vboAddress)]; +} + +int gl::vboIndex(const VboAddress vboAddress) +{ + return static_cast(vboAddress.vboClass) * gl::numVboSubclasses + + static_cast(vboAddress.vboSubclass); +} diff -r cef43609a374 -r 0133e565e072 src/gl/compiler.h --- a/src/gl/compiler.h Sat Dec 14 23:00:01 2019 +0200 +++ b/src/gl/compiler.h Wed Jan 01 17:45:56 2020 +0200 @@ -18,44 +18,45 @@ #pragma once #include "main.h" -#include "gl/partrenderer.h" #include "gl/common.h" #include "types/boundingbox.h" #include #include +class Model; +class DocumentManager; + namespace gl { class Compiler; class Renderer; + struct VboAddress + { + VboClass vboClass; + VboSubclass vboSubclass; + }; + int vboIndex(const VboAddress vboAddress); } -/* - * Compiles LDObjects into polygons for the GLRenderer to draw. - */ class gl::Compiler : public QObject, protected QOpenGLFunctions { Q_OBJECT public: - Compiler(Renderer* renderer); + Compiler(QObject* parent); ~Compiler(); - void initialize(); - Point3D modelCenter(); - void prepareVBO (int vbonum); - GLuint vbo (int vbonum) const; - int vboSize (int vbonum) const; - static int vboNumber (VboClass surface, VboSubclass complement); + void build(Model* model, DocumentManager* context); + void buildPolygon(Polygon polygon, std::vector* vboData); + void upload(const int vboIndex, const std::vector& data); + GLuint vbo(const VboAddress vboAddress) const; + int vboSize(const VboAddress vboAddress) const; + QColor getColorForPolygon(const gl::Polygon& polygon, VboSubclass subclass); + void writeColor(std::vector* data, const gl::Polygon& polygon, VboSubclass subclass); private: - struct ObjectVboData - { - QVector data[gl::numVbos]; - }; - QMap m_objectInfo; - QSet m_staged; // Objects that need to be compiled - GLuint m_vbo[gl::numVbos]; + void initializeVbo(); + GLuint storedVbo[gl::numVbos]; bool m_vboChanged[gl::numVbos] = {true}; - bool needBoundingBoxRebuild = true; - int m_vboSizes[gl::numVbos] = {0}; + int storedVboSizes[gl::numVbos] = {0}; + bool initialized = false; }; #define CHECK_GL_ERROR() { checkGLError(__FILE__, __LINE__); } diff -r cef43609a374 -r 0133e565e072 src/gl/partrenderer.cpp --- a/src/gl/partrenderer.cpp Sat Dec 14 23:00:01 2019 +0200 +++ b/src/gl/partrenderer.cpp Wed Jan 01 17:45:56 2020 +0200 @@ -2,8 +2,11 @@ #include // teapot #include "partrenderer.h" -PartRenderer::PartRenderer(QWidget* parent) : - QOpenGLWidget{parent} +PartRenderer::PartRenderer(Model* model, DocumentManager* documents, QWidget* parent) : + QOpenGLWidget{parent}, + model{model}, + documents{documents}, + compiler{new gl::Compiler{this}} { this->setMouseTracking(true); } @@ -19,6 +22,7 @@ this->initialized = true; this->rotation = QQuaternion::fromAxisAndAngle({1, 0, 0}, 30); this->rotation *= QQuaternion::fromAxisAndAngle({0, 1, 0}, 330); + this->compiler->build(this->model, this->documents); } /* @@ -62,7 +66,23 @@ glMatrixMode(GL_MODELVIEW); } +static int getGlTypeForVboClass(const gl::VboClass vboClass) +{ + switch (vboClass) + { + case gl::VboClass::Lines: + case gl::VboClass::ConditionalLines: + return GL_LINES; + case gl::VboClass::Triangles: + return GL_TRIANGLES; + case gl::VboClass::Quads: + return GL_QUADS; + } + throw std::runtime_error{"Bad vbo class passed to getGlTypeForVboClass"}; +} + // https://www.codemiles.com/c-opengl-examples/drawing-teapot-using-opengl-t9010.html?mobile=on +#include void PartRenderer::paintGL() { switch (this->renderStyle) @@ -77,7 +97,10 @@ } glMatrixMode(GL_MODELVIEW); // clear the drawing buffer. - glClear(GL_COLOR_BUFFER_BIT); + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHTING); // clear the identity matrix. glLoadIdentity(); // traslate the draw by z = -4.0 @@ -86,8 +109,37 @@ // Red color used to draw. glColor3f(0.8, 0.2, 0.1); glMultMatrixf(padMatrix(this->rotation.toRotationMatrix()).constData()); - glutSolidTeapot(1.0); - glFlush(); + //glutSolidTeapot(1.0); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + for (const gl::VboClass vboClass : {gl::VboClass::Lines, gl::VboClass::Triangles, gl::VboClass::Quads}) + { + const int vboSurfaces = this->compiler->vbo({vboClass, gl::VboSubclass::Surfaces}); + const int vboColors = this->compiler->vbo({vboClass, gl::VboSubclass::RegularColors}); + const int vboNormals = this->compiler->vbo({vboClass, gl::VboSubclass::Normals}); + const int count = this->compiler->vboSize({vboClass, gl::VboSubclass::Surfaces}) / 3; + glBindBuffer(GL_ARRAY_BUFFER, vboSurfaces); + glVertexPointer(3, GL_FLOAT, 0, nullptr); + glBindBuffer(GL_ARRAY_BUFFER, vboColors); + glColorPointer(4, GL_FLOAT, 0, nullptr); + //glBindBuffer(GL_ARRAY_BUFFER, vboNormals); + //glNormalPointer(GL_FLOAT, 0, nullptr); + glDrawArrays(getGlTypeForVboClass(vboClass), 0, count); + } + glBindBuffer(GL_ARRAY_BUFFER, 0); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + + //glFlush(); + const int glError = this->glGetError(); + if (glError != GL_NO_ERROR) + { + const QString glErrorString = QString::fromLatin1(reinterpret_cast(::gluErrorString(glError))); + QMessageBox::critical( + this, + tr("Rendering error"), + QString{"Failed to render: %1"}.arg(glErrorString)); + } } static QPointF pointToPointF(const QPoint& point) @@ -118,6 +170,11 @@ this->lastMousePosition = pointToPointF(event->pos()); } +void PartRenderer::setCompiler(gl::Compiler* compiler) +{ + this->compiler = compiler; +} + void PartRenderer::setRenderStyle(const gl::RenderStyle newStyle) { this->renderStyle = newStyle; diff -r cef43609a374 -r 0133e565e072 src/gl/partrenderer.h --- a/src/gl/partrenderer.h Sat Dec 14 23:00:01 2019 +0200 +++ b/src/gl/partrenderer.h Wed Jan 01 17:45:56 2020 +0200 @@ -4,22 +4,28 @@ #include #include "main.h" #include "gl/common.h" +#include "gl/compiler.h" class PartRenderer : public QOpenGLWidget, protected QOpenGLFunctions { + Q_OBJECT public: - PartRenderer(QWidget* parent = nullptr); + PartRenderer(Model* model, DocumentManager* documents, QWidget* parent = nullptr); protected: void initializeGL() override; void resizeGL(int width, int height) override; void paintGL() override; void mouseMoveEvent(QMouseEvent* event) override; + void setCompiler(gl::Compiler* compiler); private slots: void setRenderStyle(const gl::RenderStyle newStyle); private: + Model* const model; + DocumentManager* const documents; QPointF lastMousePosition; bool initialized = false; gl::RenderStyle renderStyle = gl::RenderStyle::Normal; QQuaternion rotation; void initializeLighting(); + gl::Compiler* compiler; }; diff -r cef43609a374 -r 0133e565e072 src/invert.cpp --- a/src/invert.cpp Sat Dec 14 23:00:01 2019 +0200 +++ b/src/invert.cpp Wed Jan 01 17:45:56 2020 +0200 @@ -20,6 +20,7 @@ #include "model.h" #include "matrix.h" #include "gl/common.h" +#include "invert.h" #if 0 /* @@ -72,21 +73,10 @@ /* * Returns a matrix that causes a flip on the given dimension. */ -Matrix4x4 flipmatrix(Axis dimension) +Matrix4x4 math::flipmatrix(const Axis dimension) { Matrix4x4 result = identity4x4; - switch (dimension) - { - case X: - result(0, 0) = -1; - break; - case Y: - result(1, 1) = -1; - break; - case Z: - result(2, 2) = -1; - break; - } + result(static_cast(dimension), static_cast(dimension)) = -1; return result; } @@ -143,16 +133,18 @@ /* * Inverts the winding of a polygon. */ -void invertPolygon(gl::Polygon& polygon) +void gl::invert(gl::Polygon& polygon) { switch (polygon.numPolygonVertices()) { case 2: case 3: + // 0 1 => 1 0 + // 0 1 2 => 1 0 2 std::swap(polygon.vertices[0], polygon.vertices[1]); break; - case 4: + // 0 1 2 3 => 0 3 2 1 std::swap(polygon.vertices[1], polygon.vertices[3]); break; } diff -r cef43609a374 -r 0133e565e072 src/invert.h --- a/src/invert.h Sat Dec 14 23:00:01 2019 +0200 +++ b/src/invert.h Wed Jan 01 17:45:56 2020 +0200 @@ -22,6 +22,14 @@ #include "gl/common.h" bool isflat(class Model* model, Axis* axis); -QMatrix4x4 flipmatrix(Axis dimension); + +namespace math +{ + Matrix4x4 flipmatrix(Axis dimension); +} //void invert(LDObject* obj, class DocumentManager* context); -void invertPolygon(gl::Polygon& polygon); + +namespace gl +{ + void invert(gl::Polygon& polygon); +} diff -r cef43609a374 -r 0133e565e072 src/linetypes/edge.cpp --- a/src/linetypes/edge.cpp Sat Dec 14 23:00:01 2019 +0200 +++ b/src/linetypes/edge.cpp Wed Jan 01 17:45:56 2020 +0200 @@ -48,3 +48,11 @@ { return utility::format("%1 %2", vertexToStringParens(point_1), vertexToStringParens(point_2)); } + +void linetypes::Edge::getPolygons( + std::vector& polygons, + GetPolygonsContext* context) const +{ + Q_UNUSED(context) + polygons.push_back(gl::edgeLine(this->point_1, this->point_2, this->colorIndex, this->id)); +} diff -r cef43609a374 -r 0133e565e072 src/linetypes/edge.h --- a/src/linetypes/edge.h Sat Dec 14 23:00:01 2019 +0200 +++ b/src/linetypes/edge.h Wed Jan 01 17:45:56 2020 +0200 @@ -19,6 +19,7 @@ Property property, const QVariant& value) override; QString textRepresentation() const override; + void getPolygons(std::vector& polygons, GetPolygonsContext* context) const override; private: Point3D point_1 = {}; Point3D point_2 = {}; diff -r cef43609a374 -r 0133e565e072 src/linetypes/object.cpp --- a/src/linetypes/object.cpp Sat Dec 14 23:00:01 2019 +0200 +++ b/src/linetypes/object.cpp Wed Jan 01 17:45:56 2020 +0200 @@ -52,6 +52,12 @@ return {}; } +void linetypes::Object::getPolygons(std::vector& polygons, GetPolygonsContext* context) const +{ + Q_UNUSED(polygons) + Q_UNUSED(context) +} + linetypes::ColoredObject::ColoredObject(const Color color_index) : colorIndex{color_index} { diff -r cef43609a374 -r 0133e565e072 src/linetypes/object.h --- a/src/linetypes/object.h Sat Dec 14 23:00:01 2019 +0200 +++ b/src/linetypes/object.h Wed Jan 01 17:45:56 2020 +0200 @@ -5,16 +5,24 @@ #include "main.h" #include "colors.h" #include "vertex.h" +#include "gl/common.h" namespace linetypes { - struct Id { unsigned int value; }; + struct GetPolygonsContext; enum class Property; class Object; class ColoredObject; class Empty; } +class DocumentManager; + +struct linetypes::GetPolygonsContext +{ + ::DocumentManager* documents; +}; + /** * @brief Different properties that can be queried with getProperty */ @@ -28,8 +36,7 @@ Point4, // Fourth vertex in a quadrilateral ControlPoint1, // First control point in a conditional edge line ControlPoint2, // Second control point in a conditional edge line - Position, // Position of a subfile reference - Transformation, // Transformation matrix of a subfile reference + Transformation, // 4x4 transformation matrix of a subfile reference ReferenceName, // Subfile reference name IsInverted, // Whether or not the object has been inverted with BFC INVERTNEXT ErrorMessage // For error lines, why parsing failed @@ -56,6 +63,7 @@ virtual QBrush textRepresentationForeground() const; virtual QBrush textRepresentationBackground() const; virtual QFont textRepresentationFont() const; + virtual void getPolygons(std::vector& polygons, GetPolygonsContext* context) const; }; class linetypes::ColoredObject : public Object @@ -65,7 +73,7 @@ bool hasColor() const override final; QVariant getProperty(Property id) const override; SetPropertyResult setProperty(Property id, const QVariant& value) override; -private: +protected: Color colorIndex = colors::main; }; diff -r cef43609a374 -r 0133e565e072 src/linetypes/quadrilateral.cpp --- a/src/linetypes/quadrilateral.cpp Sat Dec 14 23:00:01 2019 +0200 +++ b/src/linetypes/quadrilateral.cpp Wed Jan 01 17:45:56 2020 +0200 @@ -64,5 +64,19 @@ vertexToStringParens(points[0]), vertexToStringParens(points[1]), vertexToStringParens(points[2]), - vertexToStringParens(points[3])); + vertexToStringParens(points[3])); } + +void linetypes::Quadrilateral::getPolygons( + std::vector& polygons, + GetPolygonsContext* context) const +{ + Q_UNUSED(context) + polygons.push_back(gl::quadrilateral( + this->points[0], + this->points[1], + this->points[2], + this->points[3], + this->colorIndex, + this->id)); +} diff -r cef43609a374 -r 0133e565e072 src/linetypes/quadrilateral.h --- a/src/linetypes/quadrilateral.h Sat Dec 14 23:00:01 2019 +0200 +++ b/src/linetypes/quadrilateral.h Wed Jan 01 17:45:56 2020 +0200 @@ -20,6 +20,7 @@ QVariant getProperty(Property id) const override; SetPropertyResult setProperty(Property id, const QVariant& value) override; QString textRepresentation() const override; + void getPolygons(std::vector& polygons, GetPolygonsContext* context) const override; private: Point3D points[4] = {{}}; }; diff -r cef43609a374 -r 0133e565e072 src/linetypes/subfilereference.cpp --- a/src/linetypes/subfilereference.cpp Sat Dec 14 23:00:01 2019 +0200 +++ b/src/linetypes/subfilereference.cpp Wed Jan 01 17:45:56 2020 +0200 @@ -1,12 +1,10 @@ #include "subfilereference.h" +#include "documentmanager.h" -linetypes::SubfileReference::SubfileReference( - const Point3D& position, - const Matrix3x3& transformation, +linetypes::SubfileReference::SubfileReference(const Matrix4x4& transformation, const QString& referenceName, const Color color) : ColoredObject{color}, - position{position}, transformation{transformation}, referenceName{referenceName} { @@ -16,8 +14,6 @@ { switch (property) { - case Property::Position: - return this->position; case Property::Transformation: return QVariant::fromValue(this->transformation); case Property::ReferenceName: @@ -34,11 +30,8 @@ { switch (property) { - case Property::Position: - this->position = value.value(); - return SetPropertyResult::Success; case Property::Transformation: - this->transformation = value.value(); + this->transformation = value.value(); return SetPropertyResult::Success; case Property::ReferenceName: this->referenceName = value.toString(); @@ -50,5 +43,40 @@ QString linetypes::SubfileReference::textRepresentation() const { - return referenceName + " " + vertexToStringParens(this->position); + return referenceName + " " + vertexToStringParens(this->position()); } + +void linetypes::SubfileReference::getPolygons( + std::vector& polygons, + GetPolygonsContext* context) const +{ + Model* model = this->resolve(context->documents); + if (model != nullptr) + { + const std::vector modelPolygons = model->getPolygons(context->documents); + polygons.reserve(polygons.size() + modelPolygons.size()); + for (gl::Polygon polygon : modelPolygons) + { + for (int i = 0; i < polygon.numPolygonVertices(); i += 1) + { + polygon.vertices[i] = math::transform(polygon.vertices[1], this->transformation); + } + if (polygon.color == colors::main) + { + polygon.color = this->colorIndex; + } + polygon.id = this->id; + polygons.push_back(polygon); + } + } +} + +Point3D linetypes::SubfileReference::position() const +{ + return {this->transformation(0, 3), this->transformation(1, 3), this->transformation(2, 3)}; +} + +Model* linetypes::SubfileReference::resolve(DocumentManager* documents) const +{ + return documents->findModelByName(this->referenceName); +} diff -r cef43609a374 -r 0133e565e072 src/linetypes/subfilereference.h --- a/src/linetypes/subfilereference.h Sat Dec 14 23:00:01 2019 +0200 +++ b/src/linetypes/subfilereference.h Wed Jan 01 17:45:56 2020 +0200 @@ -2,6 +2,8 @@ #include "object.h" #include "matrix.h" +class Model; + namespace linetypes { class SubfileReference; @@ -12,15 +14,16 @@ public: SubfileReference() = default; SubfileReference( - const Point3D& position, - const Matrix3x3& transformation, + const Matrix4x4& transformation, const QString &referenceName, const Color color = colors::main); QVariant getProperty(Property property) const override; SetPropertyResult setProperty(Property property, const QVariant& value) override; QString textRepresentation() const override; + void getPolygons(std::vector& polygons, GetPolygonsContext* context) const override; + Point3D position() const; private: - Point3D position; - Matrix3x3 transformation; + Model* resolve(DocumentManager* documents) const; + Matrix4x4 transformation; QString referenceName; }; diff -r cef43609a374 -r 0133e565e072 src/linetypes/triangle.cpp --- a/src/linetypes/triangle.cpp Sat Dec 14 23:00:01 2019 +0200 +++ b/src/linetypes/triangle.cpp Wed Jan 01 17:45:56 2020 +0200 @@ -57,3 +57,16 @@ vertexToStringParens(points[1]), vertexToStringParens(points[2])); } + +void linetypes::Triangle::getPolygons( + std::vector& polygons, + GetPolygonsContext* context) const +{ + Q_UNUSED(context) + polygons.push_back(gl::triangle( + this->points[0], + this->points[1], + this->points[2], + this->colorIndex, + this->id)); +} diff -r cef43609a374 -r 0133e565e072 src/linetypes/triangle.h --- a/src/linetypes/triangle.h Sat Dec 14 23:00:01 2019 +0200 +++ b/src/linetypes/triangle.h Wed Jan 01 17:45:56 2020 +0200 @@ -18,6 +18,7 @@ QVariant getProperty(Property id) const override; SetPropertyResult setProperty(Property id, const QVariant& value) override; QString textRepresentation() const override; + void getPolygons(std::vector& polygons, GetPolygonsContext* context) const override; private: Point3D points[3] = {{}}; }; diff -r cef43609a374 -r 0133e565e072 src/main.h --- a/src/main.h Sat Dec 14 23:00:01 2019 +0200 +++ b/src/main.h Wed Jan 01 17:45:56 2020 +0200 @@ -12,3 +12,12 @@ // List of setting groups constexpr char mainwindow[] = "mainwindow"; } + +namespace linetypes +{ + // Uniquely identifies a model body object + struct Id + { + unsigned int value; + }; +} diff -r cef43609a374 -r 0133e565e072 src/mainwindow.cpp --- a/src/mainwindow.cpp Sat Dec 14 23:00:01 2019 +0200 +++ b/src/mainwindow.cpp Wed Jan 01 17:45:56 2020 +0200 @@ -117,7 +117,7 @@ void MainWindow::openModelForEditing(const QString& modelName) { - Document* document = new Document{this->documents.findModelByName(modelName)}; + Document* document = new Document{this->documents.findModelByName(modelName), &this->documents}; this->ui->tabs->addTab(document, modelName); this->ui->tabs->setCurrentWidget(document); document->restoreSplitterState(this->documentSplitterState); diff -r cef43609a374 -r 0133e565e072 src/matrix.cpp --- a/src/matrix.cpp Sat Dec 14 23:00:01 2019 +0200 +++ b/src/matrix.cpp Wed Jan 01 17:45:56 2020 +0200 @@ -1,1 +1,12 @@ #include "matrix.h" +#include "vertex.h" + +Matrix4x4 combine(const Matrix3x3& topLeft, const Point3D& translation) +{ + return {{ + {topLeft(0, 0), topLeft(0, 1), topLeft(0, 2), translation.x}, + {topLeft(1, 0), topLeft(1, 1), topLeft(1, 2), translation.y}, + {topLeft(2, 0), topLeft(2, 1), topLeft(2, 2), translation.z}, + {0, 0, 0, 1} + }}; +} diff -r cef43609a374 -r 0133e565e072 src/matrix.h --- a/src/matrix.h Sat Dec 14 23:00:01 2019 +0200 +++ b/src/matrix.h Wed Jan 01 17:45:56 2020 +0200 @@ -146,5 +146,7 @@ return stream; } +Matrix4x4 combine(const Matrix3x3& topLeft, const struct Point3D& translation); + static constexpr Matrix3x3 identity3x3 {{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}}; static constexpr Matrix4x4 identity4x4 {{{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}}}; diff -r cef43609a374 -r 0133e565e072 src/model.cpp --- a/src/model.cpp Sat Dec 14 23:00:01 2019 +0200 +++ b/src/model.cpp Wed Jan 01 17:45:56 2020 +0200 @@ -3,10 +3,8 @@ #include "model.h" #include "modeleditcontext.h" -Model::Model() -{ - -} +Model::Model(QObject* parent) : + QAbstractListModel{parent} {} int Model::size() const { @@ -59,6 +57,30 @@ return object->getProperty(property); } +std::vector Model::getPolygons(DocumentManager* documents) const +{ + if (this->needRecache) + { + this->cachedPolygons.clear(); + linetypes::GetPolygonsContext context{documents}; + for (int i = 0; i < this->size(); i += 1) + { + this->getObjectPolygons(i, this->cachedPolygons, &context); + } + this->needRecache = false; + } + return this->cachedPolygons; +} + +void Model::getObjectPolygons( + const int index, + std::vector& polygons_out, + linetypes::GetPolygonsContext* context) const +{ + const linetypes::Object* object = this->body[index].get(); + object->getPolygons(polygons_out, context); +} + void Model::append(ModelObjectPointer&& object) { this->body.push_back(std::move(object)); diff -r cef43609a374 -r 0133e565e072 src/model.h --- a/src/model.h Sat Dec 14 23:00:01 2019 +0200 +++ b/src/model.h Wed Jan 01 17:45:56 2020 +0200 @@ -4,6 +4,7 @@ #include "main.h" #include "header.h" #include "linetypes/object.h" +#include "gl/common.h" enum class HeaderProperty { @@ -15,7 +16,7 @@ Q_OBJECT public: class EditContext; - Model(); + Model(QObject* parent = nullptr); Model(const Model&) = delete; int size() const; EditContext edit(); @@ -24,6 +25,8 @@ QVariant getHeaderProperty(const HeaderProperty property); const QString& getName() const; QVariant getObjectProperty(const int index, const linetypes::Property property) const; + std::vector getPolygons(class DocumentManager* documents) const; + void getObjectPolygons(const int index, std::vector& polygons_out, linetypes::GetPolygonsContext* context) const; signals: void objectAdded(linetypes::Id id, int position); private: @@ -38,6 +41,8 @@ LDHeader header; std::vector body; std::map objectsById; + mutable std::vector cachedPolygons; + mutable bool needRecache = true; }; template diff -r cef43609a374 -r 0133e565e072 src/parser.cpp --- a/src/parser.cpp Sat Dec 14 23:00:01 2019 +0200 +++ b/src/parser.cpp Wed Jan 01 17:45:56 2020 +0200 @@ -350,7 +350,7 @@ const Point3D position = vertexFromStrings(tokens, positionPosition); const Matrix3x3 transform = matrixFromStrings(tokens, transformPosition); const QString& name = tokens[namePosition]; - return std::make_unique(position, transform, name, color); + return std::make_unique(combine(transform, position), name, color); } template diff -r cef43609a374 -r 0133e565e072 src/vertex.cpp --- a/src/vertex.cpp Sat Dec 14 23:00:01 2019 +0200 +++ b/src/vertex.cpp Wed Jan 01 17:45:56 2020 +0200 @@ -157,20 +157,23 @@ } /* - * Transforms this vertex with a tranformation matrix and returns the result. + * Transforms the specified vertex with a transformation matrix */ -Point3D math::transform(const Point3D point, const GLRotationMatrix& matrix) +Point3D math::transform(const Point3D& point, const Matrix4x4& matrix) { return { matrix(0, 0) * point.x + matrix(0, 1) * point.y - + matrix(0, 2) * point.z, + + matrix(0, 2) * point.z + + matrix(0, 3), matrix(1, 0) * point.x + matrix(1, 1) * point.y - + matrix(1, 2) * point.z, + + matrix(1, 2) * point.z + + matrix(1, 3), matrix(2, 0) * point.x + matrix(2, 1) * point.y - + matrix(2, 2) * point.z, + + matrix(2, 2) * point.z + + matrix(2, 3), }; } diff -r cef43609a374 -r 0133e565e072 src/vertex.h --- a/src/vertex.h Sat Dec 14 23:00:01 2019 +0200 +++ b/src/vertex.h Wed Jan 01 17:45:56 2020 +0200 @@ -21,6 +21,7 @@ #include #include "basics.h" #include "maths.h" +#include "matrix.h" struct Point3D { @@ -34,7 +35,7 @@ namespace math { - Point3D transform(const Point3D point, const GLRotationMatrix& matrix); + Point3D transform(const Point3D& point, const Matrix4x4& matrix); qreal distance(const Point3D& one, const Point3D& other); }