# HG changeset patch # User Teemu Piippo # Date 1576355766 -7200 # Node ID ed9685f44ab36366590ad2c3e08e07a119d8e046 # Parent 918b6c0f8b5b5d29121d5d29d75d738a12086ead added missing files diff -r 918b6c0f8b5b -r ed9685f44ab3 src/gl/common.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gl/common.h Sat Dec 14 22:36:06 2019 +0200 @@ -0,0 +1,158 @@ +/* + * 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 . + */ + +#pragma once +#include +#include +#include +#include "basics.h" +#include "colors.h" +#include "vertex.h" + +namespace gl +{ + // Transformation matrices for projection cameras. + static const QMatrix4x4 topCameraMatrix = {}; + static const QMatrix4x4 frontCameraMatrix = {1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1}; + static const QMatrix4x4 leftCameraMatrix = {0, -1, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 1}; + static const QMatrix4x4 bottomCameraMatrix = {1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1}; + static const QMatrix4x4 backCameraMatrix = {-1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1}; + static const QMatrix4x4 rightCameraMatrix = {0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1}; + + // Conversion matrix from LDraw to OpenGL coordinates. + static const QMatrix4x4 ldrawToGL = {1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1}; + + static constexpr QRgb BlackRgb = 0xff000000; + static constexpr GLfloat near = 1.0f; + static constexpr GLfloat far = 10000.0f; + struct Polygon; +} + +struct gl::Polygon +{ + enum Type : qint8 + { + EdgeLine, + Triangle, + Quadrilateral, + ConditionalEdge + }; + Type type; + Point3D vertices[4]; + Color color; + + /** + * @return amount of vertices used for geometry + */ + inline int numPolygonVertices() const + { + if (type == Type::ConditionalEdge) + return 2; + else + return numVertices(); + } + + /** + * @return amount of vertices + */ + inline int numVertices() const + { + switch (type) + { + case Type::EdgeLine: + return 2; + case Type::Triangle: + return 3; + case Type::ConditionalEdge: + case Type::Quadrilateral: + return 4; + default: + return 0; + } + } +}; + +Q_DECLARE_METATYPE(gl::Polygon) + +namespace gl +{ + inline Polygon edgeLine(const Point3D& v_1, const Point3D& v_2, Color color) + { + return {Polygon::EdgeLine, {v_1, v_2}, color}; + } + + inline Polygon triangle(const Point3D& v_1, const Point3D& v_2, const Point3D& v_3, Color color) + { + return {Polygon::Triangle, {v_1, v_2, v_3}, color}; + } + + inline Polygon quadrilateral( + const Point3D& v_1, + const Point3D& v_2, + const Point3D& v_3, + const Point3D& v_4, + Color color) + { + return {Polygon::Quadrilateral, {v_1, v_2, v_3, v_4}, color}; + } + + inline Polygon conditionalEdge( + const Point3D& v_1, + const Point3D& v_2, + const Point3D& control_1, + const Point3D& control_2, + Color color) + { + return {Polygon::ConditionalEdge, {v_1, v_2, control_1, control_2}, color}; + } + + // Vbo names + enum class VboClass + { + Lines, + Triangles, + Quads, + ConditionalLines + }; + constexpr int numVboClasses = 4; + + // Types of vbo per object + enum class VboSubclass + { + Surfaces, + RegularColors, + PickColors, + BfcFrontColors, + BfcBackColors, + RandomColors, + Normals, + InvertedNormals + }; + constexpr int numVboSubclasses = 8; + + // Amount of vbos overall + constexpr int numVbos = gl::numVboClasses * gl::numVboSubclasses; + + enum class RenderStyle + { + Normal, + Wireframe, + BfcRedGreen, + RandomColors + }; +} diff -r 918b6c0f8b5b -r ed9685f44ab3 src/gl/compiler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gl/compiler.cpp Sat Dec 14 22:36:06 2019 +0200 @@ -0,0 +1,30 @@ +/* + * 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 . + */ + +#define GL_GLEXT_PROTOTYPES +#include +#include +#include "gl/compiler.h" +#include "documentmanager.h" +#include "invert.h" +#include "ring.h" + +gl::Compiler::~Compiler() +{ + +} diff -r 918b6c0f8b5b -r ed9685f44ab3 src/gl/compiler.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gl/compiler.h Sat Dec 14 22:36:06 2019 +0200 @@ -0,0 +1,62 @@ +/* + * 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 . + */ + +#pragma once +#include "main.h" +#include "gl/partrenderer.h" +#include "gl/common.h" +#include "types/boundingbox.h" +#include +#include + +namespace gl +{ + class Compiler; + class Renderer; +} + +/* + * Compiles LDObjects into polygons for the GLRenderer to draw. + */ +class gl::Compiler : public QObject, protected QOpenGLFunctions +{ + Q_OBJECT +public: + Compiler(Renderer* renderer); + ~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); +private: + struct ObjectVboData + { + QVector data[gl::numVbos]; + }; + QMap m_objectInfo; + QSet m_staged; // Objects that need to be compiled + GLuint m_vbo[gl::numVbos]; + bool m_vboChanged[gl::numVbos] = {true}; + bool needBoundingBoxRebuild = true; + int m_vboSizes[gl::numVbos] = {0}; +}; + +#define CHECK_GL_ERROR() { checkGLError(__FILE__, __LINE__); } +void checkGLError (QString file, int line); diff -r 918b6c0f8b5b -r ed9685f44ab3 src/invert.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/invert.cpp Sat Dec 14 22:36:06 2019 +0200 @@ -0,0 +1,159 @@ +/* + * 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 "main.h" +#include "model.h" +#include "matrix.h" +#include "gl/common.h" + +#if 0 +/* + * Returns whether or not the document is flat. + * If it is flat, the result is stored in *axis. + */ +bool isflat(Model* model, Axis* flatDimension) +{ + // The dimensions that this model is potentially flat in. + QVector dimensions = {X, Y, Z}; + + // Iterate through everything in the subfile. If there is any vertex with a coordinate not at + // zero, the subfile is not flat in that dimension. + for (LDObject* subfileObject : model->objects()) + { + for (int i = 0; i < subfileObject->numVertices(); ++i) + { + Vertex const& v_i = subfileObject->vertex(i); + + if (not qFuzzyCompare(v_i.x, 0.0)) + dimensions.removeOne(X); + + if (not qFuzzyCompare(v_i.y, 0.0)) + dimensions.removeOne(Y); + + if (not qFuzzyCompare(v_i.z, 0.0)) + dimensions.removeOne(Z); + } + + // If there are no more dimensions left, we can exit the loop. + if (dimensions.isEmpty()) + break; + } + + if (dimensions.size() == 1) + { + // The model is flat in one dimension, return that. + // If the model is flat in two or three dimensions, it's not really a valid model. + *flatDimension = dimensions[0]; + return true; + } + else + { + // The model is not flat. + return false; + } +} +#endif + +/* + * Returns a matrix that causes a flip on the given dimension. + */ +Matrix4x4 flipmatrix(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; + } + return result; +} + +#if 0 +/* + * Inverts an LDObject so that its winding is changed. + */ +void invert(LDObject* obj, DocumentManager* context) +{ + if (obj->numPolygonVertices() > 0) + { + // Object is vertex based, so change the order of the vertices. + QVector vertices; + vertices.resize(obj->numPolygonVertices()); + + for (int i = 0; i < vertices.size(); i += 1) + vertices[vertices.size() - 1 - i] = obj->vertex(i); + + for (int i = 0; i < vertices.size(); i += 1) + obj->setVertex(i, vertices[i]); + } + else if (obj->type() == LDObjectType::SubfileReference) + { + // Check whether subfile is flat. If it is, flip it on the axis on which it is flat. + Model model {context}; + LDSubfileReference* reference = static_cast(obj); + reference->fileInfo(context)->inlineContents(model, true, false); + Axis flatDimension; + + if (::isflat(&model, &flatDimension)) + { + reference->setTransformationMatrix( + reference->transformationMatrix() * ::flipmatrix(flatDimension) + ); + } + else + { + // Subfile is not flat. Resort to invertnext. + reference->setInverted(not reference->isInverted()); + } + } + else if (obj->type() == LDObjectType::CircularPrimitive) + { + auto primitive = static_cast(obj); + + if (primitive->isFlat()) + primitive->setTransformationMatrix(primitive->transformationMatrix() * ::flipmatrix(Y)); + else + primitive->setInverted(not primitive->isInverted()); + } +} +#endif + +/* + * Inverts the winding of a polygon. + */ +void invertPolygon(gl::Polygon& polygon) +{ + switch (polygon.numPolygonVertices()) + { + case 2: + case 3: + std::swap(polygon.vertices[0], polygon.vertices[1]); + break; + + case 4: + std::swap(polygon.vertices[1], polygon.vertices[3]); + break; + } +} diff -r 918b6c0f8b5b -r ed9685f44ab3 src/invert.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/invert.h Sat Dec 14 22:36:06 2019 +0200 @@ -0,0 +1,27 @@ +/* + * 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 . + */ + +#pragma once +#include "main.h" +#include "matrix.h" +#include "gl/common.h" + +bool isflat(class Model* model, Axis* axis); +QMatrix4x4 flipmatrix(Axis dimension); +//void invert(LDObject* obj, class DocumentManager* context); +void invertPolygon(gl::Polygon& polygon); diff -r 918b6c0f8b5b -r ed9685f44ab3 src/ring.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ring.h Sat Dec 14 22:36:06 2019 +0200 @@ -0,0 +1,109 @@ +/* + * 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 . + */ + +#pragma once + +namespace iter +{ + namespace _imp + { + template + class RingAdapter; + } + + template + _imp::RingAdapter ring(T& collection); + + template + _imp::RingAdapter ring(T& collection, int count); +} + +/* + * Implements a ring adapter over T. This class corrects indices given to the element-operator so that they're within bounds. + * The maximum amount can be specified manually. + * + * Example: + * + * int A[] = {10,20,30,40}; + * ring(A)[0] == A[0 % 4] == A[0] + * ring(A)[5] == A[5 % 4] == A[1] + * ring(A)[-1] == ring(A)[-1 + 4] == A[3] + */ +template +class iter::_imp::RingAdapter +{ +private: + // The private section must come first because _collection is used in decltype() below. + T& collection; + const int count; + +public: + RingAdapter(T& collection, int count) : + collection {collection}, + count {count} {} + + template + decltype(collection[IndexType()]) operator[](IndexType index) + { + if (count == 0) + { + // Argh! ...let the collection deal with this case. + return this->collection[index]; + } + else + { + index %= this->count; + + // Fix negative modulus... + if (index < 0) + index += this->count; + + return this->collection[index]; + } + } + + int size() const + { + return this->count; + } +}; + +/* + * Convenience function for RingAdapter so that the template parameter does not have to be provided. The ring amount is assumed + * to be the amount of elements in the collection. + */ +template +iter::_imp::RingAdapter iter::ring(T& collection) +{ + return {collection, countof(collection)}; +} + +/* + * Version of ring() that allows manual specification of the count. + */ +template +iter::_imp::RingAdapter iter::ring(T& collection, int count) +{ + return {collection, count}; +} + +template +int countof(const iter::_imp::RingAdapter& ring) +{ + return ring.size(); +} diff -r 918b6c0f8b5b -r ed9685f44ab3 src/types/boundingbox.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/types/boundingbox.cpp Sat Dec 14 22:36:06 2019 +0200 @@ -0,0 +1,68 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013 - 2019 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 "boundingbox.h" + +BoundingBox& BoundingBox::operator<<(const Point3D& vertex) +{ + this->consider(vertex); + return *this; +} + +void BoundingBox::consider(const Point3D& vertex) +{ + this->minimum.x = std::min(vertex.x, this->minimum.x); + this->minimum.y = std::min(vertex.y, this->minimum.y); + this->minimum.z = std::min(vertex.z, this->minimum.z); + this->maximum.x = std::max(vertex.x, this->maximum.x); + this->maximum.y = std::max(vertex.y, this->maximum.y); + this->maximum.z = std::max(vertex.z, this->maximum.z); +} + +/* + * Returns the length of the bounding box on the longest measure. + */ +double longestMeasure(const BoundingBox& box) +{ + double dx = box.minimum.x - box.maximum.x; + double dy = box.minimum.y - box.maximum.y; + double dz = box.minimum.z - box.maximum.z; + double size = std::max(std::max(dx, dy), dz); + return std::max(std::abs(size / 2.0), 1.0); +} + + +/* + * Yields the center of the bounding box. + */ +Point3D center(const BoundingBox& box) +{ + return { + (box.minimum.x + box.maximum.x) / 2, + (box.minimum.y + box.maximum.y) / 2, + (box.minimum.z + box.maximum.z) / 2 + }; +} + +/* + * Returns the length of the bounding box's space diagonal. + */ +double spaceDiagonal(const BoundingBox& box) +{ + return distance(box.minimum, box.maximum); +} diff -r 918b6c0f8b5b -r ed9685f44ab3 src/types/boundingbox.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/types/boundingbox.h Sat Dec 14 22:36:06 2019 +0200 @@ -0,0 +1,35 @@ +/* + * 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 . + */ + +#pragma once +#include "vertex.h" +#include "math.h" + +class BoundingBox +{ +public: + void consider(const Point3D& vertex); + Point3D minimum {math::infinity, math::infinity, math::infinity}; + Point3D maximum {-math::infinity, -math::infinity, -math::infinity}; + BoundingBox& operator<<(const Point3D& v); +}; + +static constexpr BoundingBox emptyBoundingBox = {}; +Point3D center(const BoundingBox& box); +double longestMeasure(const BoundingBox& box); +double spaceDiagonal(const BoundingBox& box);