# HG changeset patch # User Teemu Piippo # Date 1655067577 -10800 # Node ID 34c6e7bc4ee1322893d1a306592f151c83989fb6 # Parent 8e1fe64ce4e3f565c5f4475c2666c764d3005f9f Reimplement the axes program as a layer that can be added to PartRenderer diff -r 8e1fe64ce4e3 -r 34c6e7bc4ee1 CMakeLists.txt --- a/CMakeLists.txt Sun Jun 12 20:47:04 2022 +0300 +++ b/CMakeLists.txt Sun Jun 12 23:59:37 2022 +0300 @@ -39,14 +39,14 @@ src/gl/axesprogram.cpp src/gl/basicshaderprogram.cpp src/gl/compiler.cpp - src/gl/gridprogram.cpp +# src/gl/gridprogram.cpp src/gl/partrenderer.cpp - src/gl/vertexprogram.cpp +# src/gl/vertexprogram.cpp src/settingseditor/keyboardshortcutseditor.cpp src/settingseditor/librarieseditor.cpp src/settingseditor/settingseditor.cpp src/types/boundingbox.cpp - src/ui/canvas.cpp +# src/ui/canvas.cpp src/ui/multiplyfactordialog.cpp src/ui/objecteditor.cpp src/widgets/colorbutton.cpp @@ -77,14 +77,14 @@ src/gl/basicshaderprogram.h src/gl/common.h src/gl/compiler.h - src/gl/gridprogram.h +# src/gl/gridprogram.h src/gl/partrenderer.h - src/gl/vertexprogram.h +# src/gl/vertexprogram.h src/settingseditor/keyboardshortcutseditor.h src/settingseditor/librarieseditor.h src/settingseditor/settingseditor.h src/types/boundingbox.h - src/ui/canvas.h +# src/ui/canvas.h src/ui/multiplyfactordialog.h src/ui/objecteditor.h src/widgets/colorbutton.h diff -r 8e1fe64ce4e3 -r 34c6e7bc4ee1 src/document.h --- a/src/document.h Sun Jun 12 20:47:04 2022 +0300 +++ b/src/document.h Sun Jun 12 23:59:37 2022 +0300 @@ -20,10 +20,26 @@ #include #include #include -#include "ui/canvas.h" #include "model.h" #include "vertexmap.h" +enum EditingMode +{ + SelectMode, + DrawMode +}; + +Q_DECLARE_METATYPE(EditingMode); + +struct DrawState +{ + std::vector polygon; + std::vector previewPolygon; + glm::vec3 previewPoint; + bool isconcave = false; + EditingMode mode = SelectMode; +}; + struct AppendToModel { ModelElement newElement; diff -r 8e1fe64ce4e3 -r 34c6e7bc4ee1 src/gl/axesprogram.cpp --- a/src/gl/axesprogram.cpp Sun Jun 12 20:47:04 2022 +0300 +++ b/src/gl/axesprogram.cpp Sun Jun 12 23:59:37 2022 +0300 @@ -18,24 +18,22 @@ #include "axesprogram.h" -const char vertexShaderSource[] = R"( +static constexpr 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; +uniform mat4 mvp; smooth out vec3 ex_color; void main() { - gl_Position = projection * view * model * vec4(in_position, 1.0); + gl_Position = mvp * vec4(in_position, 1.0); ex_color = in_color; } )"; -const char fragmentShaderSource[] = R"( +static constexpr char fragmentShaderSource[] = R"( #version 330 core out vec4 color; @@ -47,73 +45,54 @@ } )"; -namespace +void AxesLayer::initializeGL() { - struct AxesVertex + constexpr struct VertexType { glm::vec3 position; glm::vec3 color; + } data[] = { + {{10000, 0, 0}, {1, 0, 0}}, + {{0, 0, 0}, {1, 0, 0}}, + {{-10000, 0, 0}, {0.5, 0, 0}}, + {{0, 0, 0}, {0.5, 0, 0}}, + {{0, 10000, 0}, {0, 1, 0}}, + {{0, 0, 0}, {0, 1, 0}}, + {{0, -10000, 0}, {0, 0.5, 0}}, + {{0, 0, 0}, {0, 0.5, 0}}, + {{0, 0, 10000}, {0, 0, 1}}, + {{0, 0, 0}, {0, 0, 1}}, + {{0, 0, -10000}, {0, 0, 0.5}}, + {{0, 0, 0}, {0, 0, 0.5}}, }; -} - -static const AxesVertex data[] = -{ - AxesVertex{{10000, 0, 0}, {1, 0, 0}}, - AxesVertex{{0, 0, 0}, {1, 0, 0}}, - AxesVertex{{-10000, 0, 0}, {0.5, 0, 0}}, - AxesVertex{{0, 0, 0}, {0.5, 0, 0}}, - AxesVertex{{0, 10000, 0}, {0, 1, 0}}, - AxesVertex{{0, 0, 0}, {0, 1, 0}}, - AxesVertex{{0, -10000, 0}, {0, 0.5, 0}}, - AxesVertex{{0, 0, 0}, {0, 0.5, 0}}, - AxesVertex{{0, 0, 10000}, {0, 0, 1}}, - AxesVertex{{0, 0, 0}, {0, 0, 1}}, - AxesVertex{{0, 0, -10000}, {0, 0, 0.5}}, - AxesVertex{{0, 0, 0}, {0, 0, 0.5}}, -}; - -const char* AxesProgram::vertexShaderSource() const -{ - return ::vertexShaderSource; -} - -const char* AxesProgram::fragmentShaderSource() const -{ - return ::fragmentShaderSource; + constexpr int stride = sizeof(VertexType); + this->shader.initialize( + ::vertexShaderSource, + ::fragmentShaderSource, + QOpenGLBuffer::StaticDraw, + { + GLAttributeSpec{ + .type = GL_FLOAT, + .offset = offsetof(VertexType, position), + .tuplesize = 3, + .stride = stride, + }, + { + .type = GL_FLOAT, + .offset = offsetof(VertexType, color), + .tuplesize = 3, + .stride = stride, + }, + }); + this->shader.bufferData(&data[0], countof(data), sizeof data[0]); } -const void* AxesProgram::vertexData() const -{ - return ::data; -} - -GLenum AxesProgram::drawMode() const +void AxesLayer::paintGL() { - return GL_LINES; -} - -int AxesProgram::vertexSize() const -{ - return sizeof data[0]; + this->shader.draw(GL_LINES); } -int AxesProgram::vertexCount() const -{ - return countof(data); -} - -void AxesProgram::setupVertexArrays() +void AxesLayer::mvpMatrixChanged(const glm::mat4& mvpMatrix) { - 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->shader.setMvpMatrix(mvpMatrix); } - -QOpenGLBuffer::UsagePattern AxesProgram::usagePattern() const -{ - return QOpenGLBuffer::StaticDraw; -} diff -r 8e1fe64ce4e3 -r 34c6e7bc4ee1 src/gl/axesprogram.h --- a/src/gl/axesprogram.h Sun Jun 12 20:47:04 2022 +0300 +++ b/src/gl/axesprogram.h Sun Jun 12 23:59:37 2022 +0300 @@ -2,18 +2,11 @@ #include "gl/common.h" #include "gl/basicshaderprogram.h" -class AxesProgram : public AbstractBasicShaderProgram +class AxesLayer final : public RenderLayer { - Q_OBJECT + BasicShader shader; public: - using AbstractBasicShaderProgram::AbstractBasicShaderProgram; -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; - QOpenGLBuffer::UsagePattern usagePattern() const override; + void initializeGL() override; + void paintGL() override; + void mvpMatrixChanged(const glm::mat4& mvpMatrix) override; }; diff -r 8e1fe64ce4e3 -r 34c6e7bc4ee1 src/gl/basicshaderprogram.cpp --- a/src/gl/basicshaderprogram.cpp Sun Jun 12 20:47:04 2022 +0300 +++ b/src/gl/basicshaderprogram.cpp Sun Jun 12 23:59:37 2022 +0300 @@ -18,83 +18,80 @@ #include "basicshaderprogram.h" -AbstractBasicShaderProgram::AbstractBasicShaderProgram(QObject* parent) : - QObject{parent}, +BasicShader::BasicShader() : buffer{QOpenGLBuffer::VertexBuffer}, vertexShader{QOpenGLShader::Vertex}, fragmentShader{QOpenGLShader::Fragment} { } -void AbstractBasicShaderProgram::initialize() +BasicShader::~BasicShader() { - if (not isInitialized) - { - this->initializeOpenGLFunctions(); - this->isInitialized = true; - this->program.emplace(this); - gl::buildShaders(&*this->program, this->vertexShaderSource(), this->fragmentShaderSource()); - this->program->bind(); - this->buffer.create(); - this->buffer.bind(); - const QOpenGLBuffer::UsagePattern pattern = this->usagePattern(); - this->buffer.setUsagePattern(pattern); - if (pattern == QOpenGLBuffer::StaticDraw) - { - this->buffer.allocate(this->vertexData(), this->vertexCount() * this->vertexSize()); - } - this->vertexArrayObject.create(); - this->vertexArrayObject.bind(); - this->setupVertexArrays(); - this->vertexArrayObject.release(); - this->buffer.release(); - this->program->release(); - this->checkForGLErrors(); + if (this->isInitialized) { + this->teardown(); } } -void AbstractBasicShaderProgram::setViewMatrix(const glm::mat4& newViewMatrix) +void BasicShader::initialize( + const char* vertexShaderSource, + const char* fragmentShaderSource, + QOpenGLBuffer::UsagePattern usagePattern, + const std::vector& attributeSpecs) { - this->setMatrix("view", newViewMatrix); + if (not this->isInitialized) + { + this->initializeOpenGLFunctions(); + this->isInitialized = true; + this->program = std::make_unique(); + gl::buildShaders(&*this->program, vertexShaderSource, fragmentShaderSource); + this->program->bind(); + this->buffer.create(); + this->buffer.bind(); + this->buffer.setUsagePattern(usagePattern); + this->vertexArrayObject.create(); + this->vertexArrayObject.bind(); + for (std::size_t i = 0; i < attributeSpecs.size(); ++i) { + const auto& spec = attributeSpecs[i]; + this->program->enableAttributeArray(i); + this->program->setAttributeBuffer(i, spec.type, spec.offset, spec.tuplesize, spec.stride); + } + this->vertexArrayObject.release(); + this->buffer.release(); + this->program->release(); + gl::checkForGLErrors(nullptr); + } } -void AbstractBasicShaderProgram::setProjectionMatrix(const glm::mat4& newProjectionMatrix) -{ - this->setMatrix("projection", newProjectionMatrix); -} - -void AbstractBasicShaderProgram::setModelMatrix(const glm::mat4& newModelMatrix) -{ - this->setMatrix("model", newModelMatrix); -} - -void AbstractBasicShaderProgram::setMatrix(const char* name, const glm::mat4& matrix) +void BasicShader::setMvpMatrix(const glm::mat4& newMvpMatrix) { Q_ASSERT(this->isInitialized); this->program->bind(); - this->program->setUniformMatrix(name, matrix); + this->program->setUniformMatrix("mvp", newMvpMatrix); this->program->release(); - this->checkForGLErrors(); + gl::checkForGLErrors(nullptr); } -void AbstractBasicShaderProgram::draw() +void BasicShader::bufferData(const void* data, std::size_t count, std::size_t size) +{ + this->buffer.bind(); + this->buffer.allocate(data, count * size); + this->buffer.release(); + this->vertexCount = count; +} + +void BasicShader::draw(GLenum drawMode) { this->program->bind(); this->vertexArrayObject.bind(); - glDrawArrays(this->drawMode(), 0, this->vertexCount()); + glDrawArrays(drawMode, 0, this->vertexCount); this->vertexArrayObject.release(); this->program->release(); - this->checkForGLErrors(); + gl::checkForGLErrors(nullptr); } -void AbstractBasicShaderProgram::teardown() +void BasicShader::teardown() { this->vertexArrayObject.destroy(); this->buffer.destroy(); this->program.reset(); } - -void AbstractBasicShaderProgram::checkForGLErrors() -{ - gl::checkForGLErrors(qobject_cast(this->parent())); -} diff -r 8e1fe64ce4e3 -r 34c6e7bc4ee1 src/gl/basicshaderprogram.h --- a/src/gl/basicshaderprogram.h Sun Jun 12 20:47:04 2022 +0300 +++ b/src/gl/basicshaderprogram.h Sun Jun 12 23:59:37 2022 +0300 @@ -1,47 +1,36 @@ #pragma once #include "common.h" -/** - * @brief Base class for basic shader programs - * - * A basic program is a collection of a single VAO with a single VBO, - * 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 +struct GLAttributeSpec { - Q_OBJECT -public: - AbstractBasicShaderProgram(QObject* parent = nullptr); - ~AbstractBasicShaderProgram() = 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 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; - /// \returns the vertex data for the VBO - virtual const void* vertexData() const = 0; - /// \returns the size of a single vertex in bytes - virtual int vertexSize() const = 0; - /// \returns the amount of vertices in the data - virtual int vertexCount() const = 0; - /// Called during initialization to set up the VAO. Set up your vertex array attributes here. - virtual void setupVertexArrays() = 0; - // \returns what kind of elements are drawn (GL_QUADS, GL_TRIANGLES, GL_LINES, etc) - virtual GLenum drawMode() const = 0; - virtual QOpenGLBuffer::UsagePattern usagePattern() const = 0; + GLenum type; + int offset; + int tuplesize; + int stride; +}; + +//! @brief A collection of a single VAO with a single VBO, +//! a vertex shader and a fragment shader. +class BasicShader final : protected QOpenGLFunctions +{ bool isInitialized = false; QOpenGLBuffer buffer; QOpenGLShader vertexShader; QOpenGLShader fragmentShader; - std::optional program{std::nullopt}; + std::unique_ptr program = nullptr; QOpenGLVertexArrayObject vertexArrayObject; + std::size_t vertexCount = 0; +public: + BasicShader(); + ~BasicShader(); + Q_DISABLE_COPY(BasicShader) + void initialize( + const char* vertexShaderSource, + const char* fragmentShaderSource, + QOpenGLBuffer::UsagePattern usagePattern, + const std::vector& attributeSpecs); + void setMvpMatrix(const glm::mat4& newMvpMatrix); + void bufferData(const void* data, std::size_t count, std::size_t size); + void draw(GLenum drawMode); + void teardown(); }; diff -r 8e1fe64ce4e3 -r 34c6e7bc4ee1 src/gl/common.h --- a/src/gl/common.h Sun Jun 12 20:47:04 2022 +0300 +++ b/src/gl/common.h Sun Jun 12 23:59:37 2022 +0300 @@ -29,6 +29,15 @@ #include "colors.h" #include "model.h" +class RenderLayer +{ +public: + virtual void initializeGL(){} + virtual void paintGL(){} + virtual void overpaint(QPainter*){} + virtual void mvpMatrixChanged(const glm::mat4& mvpMatrix) = 0; +}; + namespace gl { class ShaderProgram; diff -r 8e1fe64ce4e3 -r 34c6e7bc4ee1 src/gl/partrenderer.cpp --- a/src/gl/partrenderer.cpp Sun Jun 12 20:47:04 2022 +0300 +++ b/src/gl/partrenderer.cpp Sun Jun 12 23:59:37 2022 +0300 @@ -46,6 +46,18 @@ this->needBuild = true; }); connect(model, &Model::rowsRemoved, [&]{ this->needBuild = true; }); + const auto updateLayerMvpMatrix = [this]{ + const glm::mat4 newMvpMatrix = this->projectionMatrix * this->viewMatrix * this->modelMatrix; + for (RenderLayer* layer : this->activeRenderLayers) { + layer->mvpMatrixChanged(newMvpMatrix); + } + for (RenderLayer* layer : this->inactiveRenderLayers) { + layer->mvpMatrixChanged(newMvpMatrix); + } + }; + connect(this, &PartRenderer::modelMatrixChanged, updateLayerMvpMatrix); + connect(this, &PartRenderer::viewMatrixChanged, updateLayerMvpMatrix); + connect(this, &PartRenderer::projectionMatrixChanged, updateLayerMvpMatrix); } PartRenderer::~PartRenderer() @@ -69,6 +81,12 @@ abort(); } gl::initializeModelShaders(&this->shaders); + for (RenderLayer* layer : this->activeRenderLayers) { + layer->initializeGL(); + } + for (RenderLayer* layer : this->inactiveRenderLayers) { + layer->initializeGL(); + } connect(this->model, &Model::dataChanged, this, &PartRenderer::build); this->initialized = true; this->modelQuaternion = glm::angleAxis(glm::radians(30.0f), glm::vec3{-1, 0, 0}); @@ -111,6 +129,9 @@ glEnable(GL_DEPTH_TEST); glShadeModel(GL_SMOOTH); this->renderScene(); + for (RenderLayer* layer : this->activeRenderLayers) { + layer->paintGL(); + } } void PartRenderer::renderScene() @@ -296,6 +317,23 @@ this->update(); } +void PartRenderer::addRenderLayer(RenderLayer* layer) +{ + this->activeRenderLayers.push_back(layer); + this->update(); +} + +void PartRenderer::setLayerEnabled(RenderLayer* layer, bool enabled) +{ + auto& from = enabled ? this->inactiveRenderLayers : this->activeRenderLayers; + auto& to = enabled ? this->activeRenderLayers : this->inactiveRenderLayers; + auto it = std::find(from.begin(), from.end(), layer); + if (it != from.end()) { + from.erase(it); + to.push_back(layer); + } +} + /** * @brief Converts the specified on the screen into the 3D world. The point is unprojected twice into 3D and the * intersection of the resulting line with the specified plane is returned. If the intersection point lies behind diff -r 8e1fe64ce4e3 -r 34c6e7bc4ee1 src/gl/partrenderer.h --- a/src/gl/partrenderer.h Sun Jun 12 20:47:04 2022 +0300 +++ b/src/gl/partrenderer.h Sun Jun 12 23:59:37 2022 +0300 @@ -18,6 +18,8 @@ ~PartRenderer() override; void setRenderPreferences(const gl::RenderPreferences& newPreferences); ModelId getHighlightedObject() const; + void addRenderLayer(RenderLayer* layer); + void setLayerEnabled(RenderLayer* layer, bool enabled); protected: ModelId pick(QPoint where); void initializeGL() override; @@ -58,4 +60,6 @@ bool needBuild = true; void renderVao(const gl::ArrayClass arrayClass); void checkForGLErrors(); + std::vector activeRenderLayers; + std::vector inactiveRenderLayers; }; diff -r 8e1fe64ce4e3 -r 34c6e7bc4ee1 src/main.cpp --- a/src/main.cpp Sun Jun 12 20:47:04 2022 +0300 +++ b/src/main.cpp Sun Jun 12 23:59:37 2022 +0300 @@ -7,7 +7,8 @@ #include "mainwindow.h" #include "ui_mainwindow.h" #include "version.h" -#include "ui/canvas.h" +#include "gl/axesprogram.h" +#include "gl/partrenderer.h" #include "document.h" #include "settingseditor/settingseditor.h" #include "widgets/colorselectdialog.h" @@ -31,6 +32,19 @@ } }; +class ModelData : public QObject +{ + Q_OBJECT +public: + ModelData(QObject* parent) : QObject {parent} {} + std::unique_ptr canvas; + std::unique_ptr itemSelectionModel; + std::unique_ptr tools; + std::unique_ptr axesLayer; + Model* model; +}; +#include "main.moc" + static void doQtRegistrations() { QCoreApplication::setApplicationName(::appName); @@ -51,18 +65,6 @@ } }; -class ModelData : public QObject -{ - Q_OBJECT -public: - ModelData(QObject* parent) : QObject {parent} {} - std::unique_ptr canvas; - std::unique_ptr itemSelectionModel; - std::unique_ptr tools; - Model* model; -}; -#include "main.moc" - static constexpr MemberData renderStyleButtons[] = { { offsetof(Ui_MainWindow, actionRenderStyleNormal), gl::RenderStyle::Normal }, { offsetof(Ui_MainWindow, actionRenderStyleBfc), gl::RenderStyle::BfcRedGreen }, @@ -236,6 +238,7 @@ forModel(documents, [&renderPreferences](const void*, const ModelData* data){ if (data->canvas != nullptr) { data->canvas->setRenderPreferences(*renderPreferences); + data->canvas->setLayerEnabled(data->axesLayer.get(), renderPreferences->drawAxes); } }); for (auto data : ::renderStyleButtons) { @@ -391,13 +394,18 @@ if (model != nullptr) { ModelData* data = new ModelData(&documents); data->tools = std::make_unique(model, colorTable); - data->canvas = std::make_unique(model, data->tools.get(), &documents, colorTable); + data->canvas = std::make_unique(model, &documents, colorTable); data->itemSelectionModel = std::make_unique(model); + data->axesLayer = std::make_unique(); data->model = model; + data->canvas->addRenderLayer(data->axesLayer.get()); + data->canvas->setLayerEnabled(data->axesLayer.get(), settings.drawAxes()); + documents.setModelPayload(modelId, data); QObject::connect( data->tools.get(), &EditTools::modelAction, std::bind(executeAction, model, std::placeholders::_1)); +#if 0 QObject::connect(data->itemSelectionModel.get(), &QItemSelectionModel::selectionChanged, [modelId, &documents]( const QItemSelection& selected, @@ -415,6 +423,7 @@ data->canvas->handleSelectionChange(resolve(selected), resolve(deselected)); } }); +#endif data->canvas->setRenderPreferences(renderPreferences); QObject::connect( data->tools.get(), @@ -451,11 +460,13 @@ } }); QObject::connect(ui.actionQuit, &QAction::triggered, &mainWindow, &QMainWindow::close); +#if 0 QObject::connect(ui.actionAdjustGridToView, &QAction::triggered, [&]{ if (ModelData* data = currentModelData(&ui, &documents)) { adjustGridToView(data->canvas.get()); } }); +#endif QObject::connect(ui.actionClose, &QAction::triggered, [&ui, &documents]{ if (ModelData* data = currentModelData(&ui, &documents)) { // TODO diff -r 8e1fe64ce4e3 -r 34c6e7bc4ee1 src/mainwindow.h --- a/src/mainwindow.h Sun Jun 12 20:47:04 2022 +0300 +++ b/src/mainwindow.h Sun Jun 12 23:59:37 2022 +0300 @@ -25,4 +25,3 @@ #include "documentmanager.h" #include "libraries.h" #include "uiutilities.h" -#include "ui/canvas.h" diff -r 8e1fe64ce4e3 -r 34c6e7bc4ee1 src/ui/canvas.h --- a/src/ui/canvas.h Sun Jun 12 20:47:04 2022 +0300 +++ b/src/ui/canvas.h Sun Jun 12 23:59:37 2022 +0300 @@ -9,22 +9,6 @@ class EditTools; -enum EditingMode -{ - SelectMode, - DrawMode -}; - -Q_DECLARE_METATYPE(EditingMode); - -struct DrawState -{ - std::vector polygon; - std::vector previewPolygon; - glm::vec3 previewPoint; - bool isconcave = false; - EditingMode mode = SelectMode; -}; class Canvas : public PartRenderer { Q_OBJECT