Wed, 17 Feb 2021 16:49:35 +0200
stuff
--- a/CMakeLists.txt Fri Feb 05 14:23:16 2021 +0200 +++ b/CMakeLists.txt Wed Feb 17 16:49:35 2021 +0200 @@ -44,6 +44,7 @@ src/gl/axesprogram.cpp src/gl/basicshaderprogram.cpp src/gl/compiler.cpp + src/gl/geometrypreview.cpp src/gl/gridprogram.cpp src/gl/partrenderer.cpp src/linetypes/comment.cpp @@ -96,6 +97,7 @@ src/gl/basicshaderprogram.h src/gl/common.h src/gl/compiler.h + src/gl/geometrypreview.h src/gl/gridprogram.h src/gl/partrenderer.h src/linetypes/comment.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gl/abstractshaderprogram.cpp Wed Feb 17 16:49:35 2021 +0200 @@ -0,0 +1,113 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2020 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 "abstractshaderprogram.h" + +AbstractShaderProgram::AbstractBasicShaderProgram(const QVector<ArraySpecification>& arraySpecifications, QObject* parent) : + QObject{parent}, + buffer{QOpenGLBuffer::VertexBuffer}, + vertexShader{QOpenGLShader::Vertex}, + fragmentShader{QOpenGLShader::Fragment} +{ + this->arrays.reserve(arraySpecifications.size()); + for (const ArraySpecification& arraySpecification : arraySpecifications) + { + this->arrays.emplace_back({arraySpecification}); + } +} + +void AbstractShaderProgram::initialize() +{ + if (not this->isInitialized) + { + this->initializeOpenGLFunctions(); + this->isInitialized = true; + this->program.emplace(this); + gl::buildShaders(&*this->program, this->vertexShaderSource(), this->fragmentShaderSource()); + this->program->bind(); + for (auto& array : this->arrays) + { + array.buffer.create(); + array.buffer.bind(); + array.buffer.setUsagePattern(array.specification.bufferUsagePattern); + array.vertexArrayObject.create(); + array.vertexArrayObject.bind(); + } + this->setupVertexArrays(); + this->vertexArrayObject.release(); + this->releaseBuffers(); + this->buffer.release(); + this->program->release(); + this->checkForGLErrors(); + } +} + +void AbstractShaderProgram::setViewMatrix(const glm::mat4& newViewMatrix) +{ + this->setMatrix("view", newViewMatrix); +} + +void AbstractShaderProgram::setProjectionMatrix(const glm::mat4& newProjectionMatrix) +{ + this->setMatrix("projection", newProjectionMatrix); +} + +void AbstractShaderProgram::setModelMatrix(const glm::mat4& newModelMatrix) +{ + this->setMatrix("model", newModelMatrix); +} + +void AbstractShaderProgram::setMatrix(const char* name, const glm::mat4& matrix) +{ + Q_ASSERT(this->isInitialized); + this->program->bind(); + this->program->setUniformMatrix(name, matrix); + this->program->release(); + this->checkForGLErrors(); +} + +void AbstractShaderProgram::draw() +{ + this->program->bind(); + for (Array& array : this->arrays) + { + array.vertexArrayObject.bind(); + glDrawArrays(array.specification.drawMode, 0, array.count); + this->vertexArrayObject.release(); + } + this->program->release(); + this->checkForGLErrors(); +} + +void AbstractShaderProgram::teardown() +{ + this->vertexArrayObject.destroy(); + this->buffer.destroy(); + this->program.reset(); +} + +void AbstractShaderProgram::checkForGLErrors() +{ + gl::checkForGLErrors(qobject_cast<QWidget*>(this->parent())); +} + +void AbstractShaderProgram::upload(Array* array, const void* data, int count) +{ + array->count = count; + array->buffer->buffer.allocate(data, count * array->specification.vertexSize); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gl/abstractshaderprogram.h Wed Feb 17 16:49:35 2021 +0200 @@ -0,0 +1,48 @@ +#pragma once +#include "common.h" + +/** + * @brief Base class for shader programs + */ +class AbstractShaderProgram : public QObject, protected QOpenGLFunctions +{ + Q_OBJECT +public: + struct ArraySpecification + { + GLenum drawMode; + std::size_t vertexSize; + QOpenGLBuffer::UsagePattern bufferUsagePattern = QOpenGLBuffer::StaticDraw; + }; + struct Array + { + const ArraySpecification specification; + QOpenGLBuffer buffer; + QOpenGLVertexArrayObject vertexArrayObject; + int count; + }; + AbstractShaderProgram(const QVector<ArraySpecification>& arraySpecifications, QObject* parent = nullptr); + ~AbstractShaderProgram() = default; + void initialize(); + Q_SLOT void setViewMatrix(const glm::mat4& newViewMatrix); + Q_SLOT void setProjectionMatrix(const glm::mat4& newProjectionMatrix); + Q_SLOT void setModelMatrix(const glm::mat4& newModelMatrix); + void draw(); + void teardown(); +protected: + void setMatrix(const char* name, const glm::mat4& matrix); + void upload(Array* array, const void* data, int count); + void checkForGLErrors(); + /// \returns the source code of the vertex shader + virtual const char* vertexShaderSource() const = 0; + /// \returns the source code of the fragment shader + virtual const char* fragmentShaderSource() const = 0; + /// Called during initialization to set up the VAO. Set up your vertex array attributes here. + virtual void setupVertexArrays() = 0; + + bool isInitialized = false; + QOpenGLShader vertexShader; + QOpenGLShader fragmentShader; + std::optional<gl::ShaderProgram> program{std::nullopt}; + QVector<Array> arrays; +};
--- a/src/gl/axesprogram.cpp Fri Feb 05 14:23:16 2021 +0200 +++ b/src/gl/axesprogram.cpp Wed Feb 17 16:49:35 2021 +0200 @@ -72,6 +72,11 @@ AxesVertex{{0, 0, 0}, {0, 0, 0.5}}, }; +constexpr std::size_t vertexSize = sizeof data[0]; + +AxesProgram::AxesProgram(QObject* parent) : + AbstractShaderProgram{{{GL_LINES, ::vertexSize}}, parent} {} + const char* AxesProgram::vertexShaderSource() const { return ::vertexShaderSource; @@ -87,28 +92,13 @@ return ::data; } -GLenum AxesProgram::drawMode() const -{ - return GL_LINES; -} - -int AxesProgram::vertexSize() const -{ - return sizeof data[0]; -} - -int AxesProgram::vertexCount() const -{ - return countof(data); -} - void AxesProgram::setupVertexArrays() { for (int i : {0, 1}) { this->program->enableAttributeArray(i); } - const int stride = this->vertexSize(); - this->program->setAttributeBuffer(0, GL_FLOAT, offsetof(AxesVertex, position), 3, stride); - this->program->setAttributeBuffer(1, GL_FLOAT, offsetof(AxesVertex, color), 3, stride); + this->program->setAttributeBuffer(0, GL_FLOAT, offsetof(AxesVertex, position), 3, ::vertexSize); + this->program->setAttributeBuffer(1, GL_FLOAT, offsetof(AxesVertex, color), 3, ::vertexSize); + this->upload(&this->arrays[0], ::data, countof(data)); }
--- a/src/gl/axesprogram.h Fri Feb 05 14:23:16 2021 +0200 +++ b/src/gl/axesprogram.h Wed Feb 17 16:49:35 2021 +0200 @@ -1,18 +1,14 @@ #pragma once #include "gl/common.h" -#include "gl/basicshaderprogram.h" +#include "gl/abstractshaderprogram.h" -class AxesProgram : public AbstractBasicShaderProgram +class AxesProgram : public AbstractShaderProgram { Q_OBJECT public: - using AbstractBasicShaderProgram::AbstractBasicShaderProgram; + AxesProgram(QObject* parent = nullptr); protected: const char* vertexShaderSource() const override; const char* fragmentShaderSource() const override; - const void* vertexData() const override; - GLenum drawMode() const override; - int vertexSize() const override; - int vertexCount() const override; void setupVertexArrays() override; };
--- a/src/gl/basicshaderprogram.h Fri Feb 05 14:23:16 2021 +0200 +++ b/src/gl/basicshaderprogram.h Wed Feb 17 16:49:35 2021 +0200 @@ -1,5 +1,5 @@ #pragma once -#include "common.h" +#include "abstractshaderprogram.h" /** * @brief Base class for basic shader programs @@ -8,7 +8,7 @@ * a vertex shader and a fragment shader. This program deals with these * components, leaving the program-specific details to the subclasses. */ -class AbstractBasicShaderProgram : public QObject, protected QOpenGLFunctions +class AbstractBasicShaderProgram : public AbstractShaderProgram { Q_OBJECT public:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gl/geometrypreview.cpp Wed Feb 17 16:49:35 2021 +0200 @@ -0,0 +1,108 @@ +#include "geometrypreview.h" + +const char vertexShaderSource[] = R"( +#version 330 core + +layout (location = 0) in vec3 in_position; +layout (location = 1) in vec3 in_color; +uniform mat4 view; +uniform mat4 projection; +uniform mat4 model; +smooth out vec3 ex_color; + +void main() +{ + gl_Position = projection * view * model * vec4(in_position, 1.0); + ex_color = in_color; +} +)"; + +const char fragmentShaderSource[] = R"( +#version 330 core + +out vec4 color; +smooth in vec3 ex_color; + +void main(void) +{ + color = vec4(ex_color, 1); +} +)"; + +constexpr std::size_t vertexSize = sizeof(GeometryPreview::Vertex); + +GeometryPreview::GeometryPreview(QObject *parent) : + AbstractShaderProgram{{ + {GL_LINES, vertexSize, QOpenGLBuffer::DynamicDraw}, + {GL_TRIANGLES, vertexSize, QOpenGLBuffer::DynamicDraw} + }, parent} +{ +} + +GeometryPreview::~GeometryPreview() +{ +} + +QVector<GeometryPreview::Vertex>& GeometryPreview::modifyLinesBuffer() +{ + this->needRebuild = true; + return this->lines; +} + +QVector<GeometryPreview::Vertex>& GeometryPreview::modifyTrianglesBuffer() +{ + this->needRebuild = true; + return this->triangles; +} + +void GeometryPreview::initialize() +{ + if (not this->isInitialized) + { + this->isInitialized = true; + this->program.emplace(this); + gl::buildShaders(&*this->program, ::vertexShaderSource, ::fragmentShaderSource); + this->program->bind(); + for (QOpenGLBuffer* buffer : {&this->linesBuffer, &this->trianglesBuffer}) + { + buffer->create(); + buffer->bind(); + buffer->setUsagePattern(QOpenGLBuffer::DynamicDraw); + } + this->vertexArrayObject.create(); + this->vertexArrayObject.bind(); + this->setupVertexArrays(); + this->vertexArrayObject.release(); + for (auto& buffer : {this->linesBuffer, this->trianglesBuffer}) + { + buffer->release(); + } + this->program->release(); + this->checkForGLErrors(); + } +} + +void GeometryPreview::rebuildIfNecessary() +{ + if (this->needRebuild) + { + this->buffer.allocate(this->vertexData(), this->vertexCount() * this->vertexSize()); + this->needRebuild = false; + } +} + +void GeometryPreview::checkForGLErrors() +{ + gl::checkForGLErrors(qobject_cast<QWidget*>(this->parent())); +} + +void GeometryPreview::setupVertexArrays() +{ + for (int i : {0, 1}) + { + this->program->enableAttributeArray(i); + } + const int stride = this->vertexSize(); + this->program->setAttributeBuffer(0, GL_FLOAT, offsetof(Vertex, position), 3, stride); + this->program->setAttributeBuffer(1, GL_FLOAT, offsetof(Vertex, color), 4, stride); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gl/geometrypreview.h Wed Feb 17 16:49:35 2021 +0200 @@ -0,0 +1,30 @@ +#pragma once +#include "abstractshaderprogram.h" + +class GeometryPreview : public AbstractShaderProgram +{ +public: + struct Vertex + { + glm::vec3 point; + glm::vec4 color; + }; + GeometryPreview(QObject* parent = nullptr); + ~GeometryPreview(); + QVector<Vertex>& modifyLinesBuffer(); + QVector<Vertex>& modifyTrianglesBuffer(); +private: + QVector<Vertex> lines; + QVector<Vertex> triangles; + QOpenGLBuffer linesBuffer; + QOpenGLBuffer trianglesBuffer; + QOpenGLShader vertexShader; + QOpenGLShader fragmentShader; + std::optional<gl::ShaderProgram> program{std::nullopt}; + QOpenGLVertexArrayObject vertexArrayObject; + bool isInitialized = false; + bool needRebuild = false; + void initialize(); + void rebuildIfNecessary(); + void checkForGLErrors(); +};
--- a/src/gl/gridprogram.cpp Fri Feb 05 14:23:16 2021 +0200 +++ b/src/gl/gridprogram.cpp Wed Feb 17 16:49:35 2021 +0200 @@ -63,6 +63,10 @@ )"; static const glm::vec2 data[] = {{-1, -1}, {-1, 1}, {1, 1}, {1, -1}}; +constexpr std::size_t vertexSize = sizeof data[0]; + +GridProgram::GridProgram(QObject* parent) : + AbstractShaderProgram{{{GL_QUADS, vertexSize}}, parent} void GridProgram::setGridMatrix(const glm::mat4& newGridMatrix) { @@ -95,29 +99,11 @@ return ::fragmentShaderSource; } -const void* GridProgram::vertexData() const -{ - return ::data; -} - -int GridProgram::vertexSize() const -{ - return sizeof data[0]; -} - -int GridProgram::vertexCount() const -{ - return glm::countof(data); -} - void GridProgram::setupVertexArrays() { this->program->enableAttributeArray(0); this->program->setAttributeBuffer(0, GL_FLOAT, 0, 2, 0); this->program->setUniformVector("gridColor", this->gridColor); + this->upload(&this->arrays[0], ::data, countof(data)); } -GLenum GridProgram::drawMode() const -{ - return GL_QUADS; -}
--- a/src/gl/gridprogram.h Fri Feb 05 14:23:16 2021 +0200 +++ b/src/gl/gridprogram.h Wed Feb 17 16:49:35 2021 +0200 @@ -17,14 +17,14 @@ */ #pragma once -#include "basicshaderprogram.h" +#include "abstractshaderprogram.h" #include "common.h" -class GridProgram : public AbstractBasicShaderProgram +class GridProgram : public AbstractShaderProgram { Q_OBJECT public: - using AbstractBasicShaderProgram::AbstractBasicShaderProgram; + GridProgram(QObject* parent = nullptr); void setGridMatrix(const glm::mat4& newGridMatrix); void setGridColor(const QColor& newGridColor); protected:
--- a/src/mainwindow.cpp Fri Feb 05 14:23:16 2021 +0200 +++ b/src/mainwindow.cpp Wed Feb 17 16:49:35 2021 +0200 @@ -405,3 +405,11 @@ } } } + +void MainWindow::pointInCanvasClicked(const glm::vec3& point) +{ + if (this->selectedTool != nullptr) + { + this->selectedTool->pointInCanvasClicked(point); + } +}
--- a/src/mainwindow.h Fri Feb 05 14:23:16 2021 +0200 +++ b/src/mainwindow.h Wed Feb 17 16:49:35 2021 +0200 @@ -41,6 +41,7 @@ void updateRecentlyOpenedDocumentsMenu(); void openRecentFile(); void setRenderStyle(gl::RenderStyle renderStyle); + void pointInCanvasClicked(const glm::vec3& point); protected: void changeEvent(QEvent* event) override; void closeEvent(QCloseEvent* event) override;
--- a/src/tools/basetool.h Fri Feb 05 14:23:16 2021 +0200 +++ b/src/tools/basetool.h Wed Feb 17 16:49:35 2021 +0200 @@ -24,4 +24,5 @@ virtual bool mouseDoubleClicked(QMouseEvent*) { return false; } virtual bool mouseMoved(QMouseEvent*) { return false; } virtual bool keyReleased(QKeyEvent*) { return false; } + virtual void pointInCanvasClicked(const glm::vec3&) {} };