Tue, 14 Jun 2022 17:55:50 +0300
reimplement EditTools as a render layer
src/document.cpp | file | annotate | diff | comparison | revisions | |
src/document.h | file | annotate | diff | comparison | revisions | |
src/documentmanager.cpp | file | annotate | diff | comparison | revisions | |
src/gl/common.h | file | annotate | diff | comparison | revisions | |
src/gl/compiler.h | file | annotate | diff | comparison | revisions | |
src/gl/gridprogram.cpp | file | annotate | diff | comparison | revisions | |
src/gl/gridprogram.h | file | annotate | diff | comparison | revisions | |
src/gl/partrenderer.cpp | file | annotate | diff | comparison | revisions | |
src/gl/partrenderer.h | file | annotate | diff | comparison | revisions | |
src/main.cpp | file | annotate | diff | comparison | revisions |
--- a/src/document.cpp Mon Jun 13 02:18:25 2022 +0300 +++ b/src/document.cpp Tue Jun 14 17:55:50 2022 +0300 @@ -17,65 +17,193 @@ */ #include <QMouseEvent> -#include <QMessageBox> -#include <QVBoxLayout> +#include <QPainter> #include "document.h" #include "model.h" #include "ui/objecteditor.h" +#include "gl/partrenderer.h" -EditTools::EditTools( - Model* model, - const ColorTable& colorTable, - QObject* parent) : +EditTools::EditTools(QObject* parent) : QObject{parent}, - colorTable{colorTable}, - model{model}, - vertexMap{model} + RenderLayer{} { -#if 0 - connect(this->canvas, &Canvas::mouseClick, this, &EditTools::canvasMouseClick); - connect(this->canvas, &Canvas::mouseMove, this, &EditTools::canvasMouseMove); - connect(this->canvas, &Canvas::newStatusText, this, &EditTools::newStatusText); - connect(this->model, &Model::dataChanged, this->canvas, qOverload<>(&Canvas::update)); - connect(&this->vertexMap, &VertexMap::verticesChanged, [&]() - { - this->canvas->rebuildVertices(&this->vertexMap); - }); - this->canvas->drawState = &this->drawState; -#endif } EditTools::~EditTools() { } -void EditTools::applyToVertices(VertexMap::ApplyFunction fn) const -{ - this->vertexMap.apply(fn); -} - void EditTools::setEditMode(EditingMode mode) { - this->drawState.mode = mode; + this->mode = mode; +} + +void EditTools::setGridMatrix(const glm::mat4& gridMatrix) +{ + this->gridMatrix = gridMatrix; + this->gridPlane = planeFromTriangle({ + this->gridMatrix * glm::vec4{0, 0, 0, 1}, + this->gridMatrix * glm::vec4{1, 0, 0, 1}, + this->gridMatrix * glm::vec4{0, 1, 0, 1}, + }); +} + +void EditTools::mvpMatrixChanged(const glm::mat4& matrix) +{ + this->mvpMatrix = matrix; +} + +void EditTools::mouseMoved(const QMouseEvent* event) +{ + this->worldPosition = this->renderer->screenToModelCoordinates(event->pos(), this->gridPlane); + if (this->worldPosition.has_value()) + { + // Snap the position to grid. This procedure is basically the "change of basis" and almost follows the + // A⁻¹ × M × A formula which is used to perform a transformation in some other coordinate system, except + // we actually use the inverted matrix first and the regular one last to perform the transformation of + // grid coordinates in our XY coordinate system. Also, we're rounding the coordinates which is obviously + // not a linear transformation, but fits the pattern anyway. + // First transform the coordinates to the XY plane... + this->worldPosition = glm::inverse(this->gridMatrix) * glm::vec4{*this->worldPosition, 1}; + // Then round the coordinates to integer precision... + this->worldPosition = glm::round(*this->worldPosition); + // And finally transform it back to grid coordinates by transforming it with the + // grid matrix. + this->worldPosition = this->gridMatrix * glm::vec4{*this->worldPosition, 1}; + } + this->updatePreviewPolygon(); +} + +static QVector<QPointF> convertWorldPointsToScreenPoints( + const std::vector<glm::vec3> &worldPoints, + const PartRenderer* renderer) +{ + QVector<QPointF> points2d; + points2d.reserve(worldPoints.size()); + for (const glm::vec3& point : worldPoints) + { + points2d.push_back(renderer->modelToScreenCoordinates(point)); + } + return points2d; +} + +static Winding worldPolygonWinding( + const std::vector<glm::vec3> &points, + const PartRenderer* renderer) +{ + return winding(QPolygonF{convertWorldPointsToScreenPoints(points, renderer)}); +} + +static void drawWorldPoint( + QPainter* painter, + const glm::vec3& worldPoint, + const PartRenderer* renderer) +{ + const QPointF center = renderer->modelToScreenCoordinates(worldPoint); + painter->drawEllipse(inscribe(CircleF{center, 5})); } -void updatePreviewPolygon(DrawState* drawState) +static void drawWorldPolyline( + QPainter *painter, + const std::vector<glm::vec3> &points, + const PartRenderer* renderer) +{ + painter->drawPolyline(QPolygonF{convertWorldPointsToScreenPoints(points, renderer)}); +} + +static void drawWorldPolygon( + QPainter* painter, + const std::vector<glm::vec3> &points, + const PartRenderer* renderer) +{ + painter->drawPolygon(QPolygonF{convertWorldPointsToScreenPoints(points, renderer)}); +} + +void EditTools::overpaint(QPainter* painter) { - drawState->previewPolygon = drawState->polygon; - drawState->previewPolygon.resize(drawState->polygon.size() + 1); - drawState->previewPolygon.back() = drawState->previewPoint; - if (drawState->previewPolygon.size() > 2) + struct Pens { - drawState->isconcave = not isConvex(drawState->previewPolygon); + const QBrush pointBrush; + const QPen pointPen; + const QPen polygonPen; + const QPen badPolygonPen; + const QBrush greenPolygonBrush; + const QBrush redPolygonBrush; + }; + static const Pens brightPens{ + .pointBrush = {Qt::white}, + .pointPen = {QBrush{Qt::black}, 2.0}, + .polygonPen = {QBrush{Qt::black}, 2.0, Qt::DashLine}, + .badPolygonPen = {QBrush{Qt::red}, 2.0, Qt::DashLine}, + .greenPolygonBrush = {QColor{64, 255, 128, 192}}, + .redPolygonBrush = {QColor{255, 96, 96, 192}}, + }; + static const Pens darkPens{ + .pointBrush = {Qt::black}, + .pointPen = {QBrush{Qt::white}, 2.0}, + .polygonPen = {QBrush{Qt::white}, 2.0, Qt::DashLine}, + .badPolygonPen = {QBrush{Qt::red}, 2.0, Qt::DashLine}, + .greenPolygonBrush = {QColor{64, 255, 128, 192}}, + .redPolygonBrush = {QColor{255, 96, 96, 192}}, + }; + const Pens& pens = (this->renderer->isDark() ? darkPens : brightPens); + switch(this->mode) { + case SelectMode: + break; + case DrawMode: + { + painter->setPen(this->isconcave ? pens.badPolygonPen : pens.polygonPen); + if (this->previewPolygon.size() > 2 and not this->isconcave) + { + if (worldPolygonWinding(this->previewPolygon, this->renderer) == Winding::Clockwise) { + painter->setBrush(pens.greenPolygonBrush); + } + else { + painter->setBrush(pens.redPolygonBrush); + } + drawWorldPolygon(painter, this->previewPolygon, this->renderer); + } + else { + drawWorldPolyline(painter, this->previewPolygon, this->renderer); + } + painter->setBrush(pens.pointBrush); + painter->setPen(pens.pointPen); + for (const glm::vec3& point : this->polygon) { + drawWorldPoint(painter, point, this->renderer); + } + } + break; + } + if (this->worldPosition.has_value()) + { + painter->setRenderHint(QPainter::Antialiasing); + painter->setPen(Qt::white); + painter->setBrush(Qt::green); + const QPointF pos = this->renderer->modelToScreenCoordinates(*this->worldPosition); + painter->drawEllipse(pos, 5, 5); + painter->drawText(pos + QPointF{5, 5}, vectorToString(*this->worldPosition)); } } -void removeLastPoint(DrawState* drawState) +void EditTools::updatePreviewPolygon() { - if (drawState->polygon.size() > 0) + this->previewPolygon = this->polygon; + if (this->worldPosition.has_value()) { + this->previewPolygon.resize(this->polygon.size() + 1); + this->previewPolygon.back() = *this->worldPosition; + } + if (this->previewPolygon.size() > 2) { - drawState->polygon.erase(drawState->polygon.end() - 1); - updatePreviewPolygon(drawState); + this->isconcave = not isConvex(this->previewPolygon); + } +} + +void EditTools::removeLastPoint() +{ + if (this->polygon.size() > 0) + { + this->polygon.erase(this->polygon.end() - 1); + this->updatePreviewPolygon(); } } @@ -84,106 +212,51 @@ return any(points, std::bind(isclose, std::placeholders::_1, pos)); } -void EditTools::canvasMouseClick(QMouseEvent*) +EditingMode EditTools::currentEditingMode() const { -#if 0 - switch(this->drawState.mode) - { + return this->mode; +} + +void EditTools::mouseClick(const QMouseEvent* event) +{ + switch(this->mode) { case SelectMode: - if (event->button() == Qt::LeftButton) - { - const ModelId highlighted = this->canvas->getHighlightedObject(); - QSet<ModelId> selected; - if (highlighted != ModelId{0}) { - selected.insert(highlighted); - } - //this->select(selected); - event->accept(); + if (event->button() == Qt::LeftButton) { + const ModelId highlighted = this->renderer->pick(event->pos()); + Q_EMIT this->select({highlighted}, false); } break; case DrawMode: - if (event->button() == Qt::LeftButton) { - if (isCloseToExistingPoints(this->drawState.polygon, worldPosition)) { + if (event->button() == Qt::LeftButton and this->worldPosition.has_value()) { + if (isCloseToExistingPoints(this->polygon, *this->worldPosition)) { this->closeShape(); } else { - this->drawState.polygon.push_back(pos); - updatePreviewPolygon(&this->drawState); + this->polygon.push_back(*this->worldPosition); + this->updatePreviewPolygon(); } - event->accept(); } else if (true and event->button() == Qt::RightButton - and this->drawState.polygon.size() > 0 + and this->polygon.size() > 0 ) { - this->drawState.polygon.erase(this->drawState.polygon.end() - 1); - updatePreviewPolygon(&this->drawState); - event->accept(); + this->polygon.erase(this->polygon.end() - 1); + updatePreviewPolygon(); } break; } -#endif } -void EditTools::canvasMouseMove(QMouseEvent*) -{ -#if 0 - switch(this->drawState.mode) - { - case SelectMode: - break; - case DrawMode: - if (this->canvas->worldPosition.has_value()) - { - this->drawState.previewPoint = this->canvas->worldPosition.value(); - updatePreviewPolygon(&this->drawState); - this->update(); - } - event->accept(); - break; - } -#endif -} -#if 0 -/* -void EditorTabWidget::select(const QSet<ModelId> &selected) -{ - QItemSelectionModel* selectionModel = this->ui.listView->selectionModel(); - QItemSelection itemSelection; - for (const ModelId id : selected) - { - const std::optional<int> row = this->model->find(id); - if (row.has_value()) - { - const QModelIndex qindex = this->model->index(*row); - itemSelection.select(qindex, qindex); - } - } - selectionModel->select(itemSelection, QItemSelectionModel::ClearAndSelect); -} -*/ -const QSet<ModelId> EditTools::selectedObjects() const -{ - return this->canvas->selectedObjects(); -} -#endif -EditingMode EditTools::currentEditingMode() const -{ - return this->drawState.mode; -} -#if 0 void EditTools::closeShape() { - if (this->drawState.polygon.size() >= 2 and this->drawState.polygon.size() <= 4) - { - switch (this->drawState.polygon.size()) - { + if (this->polygon.size() >= 2 and this->polygon.size() <= 4) { + switch (this->polygon.size()) { case 2: Q_EMIT this->modelAction(AppendToModel{ .newElement = Colored<LineSegment>{ LineSegment{ - .p1 = this->drawState.polygon[0], - .p2 = this->drawState.polygon[1], + .p1 = this->polygon[0], + .p2 = this->polygon[1], }, EDGE_COLOR, } @@ -193,9 +266,9 @@ Q_EMIT this->modelAction(AppendToModel{ .newElement = Colored<Triangle>{ Triangle{ - .p1 = this->drawState.polygon[0], - .p2 = this->drawState.polygon[1], - .p3 = this->drawState.polygon[2], + .p1 = this->polygon[0], + .p2 = this->polygon[1], + .p3 = this->polygon[2], }, MAIN_COLOR, } @@ -205,10 +278,10 @@ Q_EMIT this->modelAction(AppendToModel{ .newElement = Colored<Quadrilateral>{ Quadrilateral{ - .p1 = this->drawState.polygon[0], - .p2 = this->drawState.polygon[1], - .p3 = this->drawState.polygon[2], - .p4 = this->drawState.polygon[3], + .p1 = this->polygon[0], + .p2 = this->polygon[1], + .p3 = this->polygon[2], + .p4 = this->polygon[3], }, MAIN_COLOR, } @@ -216,8 +289,6 @@ break; } } - this->drawState.polygon.clear(); - updatePreviewPolygon(&this->drawState); + this->polygon.clear(); + this->updatePreviewPolygon(); } - -#endif
--- a/src/document.h Mon Jun 13 02:18:25 2022 +0300 +++ b/src/document.h Tue Jun 14 17:55:50 2022 +0300 @@ -22,6 +22,7 @@ #include <QToolBar> #include "model.h" #include "vertexmap.h" +#include "gl/common.h" enum EditingMode { @@ -31,15 +32,6 @@ Q_DECLARE_METATYPE(EditingMode); -struct DrawState -{ - std::vector<glm::vec3> polygon; - std::vector<glm::vec3> previewPolygon; - glm::vec3 previewPoint; - bool isconcave = false; - EditingMode mode = SelectMode; -}; - struct AppendToModel { ModelElement newElement; @@ -54,30 +46,37 @@ Q_DECLARE_METATYPE(ModelAction) -class EditTools : public QObject +class EditTools final : public QObject, public RenderLayer { Q_OBJECT + std::vector<glm::vec3> polygon; + std::vector<glm::vec3> previewPolygon; + glm::vec3 previewPoint; + bool isconcave = false; + EditingMode mode = SelectMode; + glm::mat4 mvpMatrix; + glm::mat4 gridMatrix{1}; + Plane gridPlane; + opt<glm::vec3> worldPosition; public: - explicit EditTools( - Model* model, - const ColorTable& colorTable, - QObject *parent = nullptr); + explicit EditTools(QObject *parent = nullptr); ~EditTools() override; void applyToVertices(VertexMap::ApplyFunction fn) const; const QSet<ModelId> selectedObjects() const; - const ColorTable& colorTable; - Model* const model; EditingMode currentEditingMode() const; Q_SLOT void setEditMode(EditingMode mode); - Q_SLOT void canvasMouseClick(QMouseEvent* event); - Q_SLOT void canvasMouseMove(QMouseEvent* event); + Q_SLOT void setGridMatrix(const glm::mat4& gridMatrix); Q_SIGNALS: void newStatusText(const QString& newStatusText); - void splitterChanged(); void modelAction(const ModelAction& action); - void drawStateChanged(const DrawState& drawState); + void select(const QSet<ModelId>& ids, bool retain); +protected: + void mvpMatrixChanged(const glm::mat4& matrix) override; + void mouseMoved(const QMouseEvent* event) override; + void mouseClick(const QMouseEvent* event) override; + void overpaint(QPainter* painter) override; private: void closeShape(); - DrawState drawState; - VertexMap vertexMap; + void updatePreviewPolygon(); + void removeLastPoint(); };
--- a/src/documentmanager.cpp Mon Jun 13 02:18:25 2022 +0300 +++ b/src/documentmanager.cpp Tue Jun 14 17:55:50 2022 +0300 @@ -37,6 +37,7 @@ { const ModelId modelId{++this->modelIdCounter}; this->openModels.emplace(std::make_pair(modelId, ModelInfo{ + .model = std::make_unique<Model>(this), .id = modelId, .opentype = OpenType::ManuallyOpened, }));
--- a/src/gl/common.h Mon Jun 13 02:18:25 2022 +0300 +++ b/src/gl/common.h Tue Jun 14 17:55:50 2022 +0300 @@ -31,11 +31,20 @@ class RenderLayer { +protected: + class PartRenderer* renderer; public: + virtual ~RenderLayer(){} virtual void initializeGL(){} virtual void paintGL(){} virtual void overpaint(QPainter*){} virtual void mvpMatrixChanged(const glm::mat4& mvpMatrix) = 0; + virtual void mouseMoved(const QMouseEvent*){} + virtual void mouseClick(const QMouseEvent*){} + void setRendererPointer(class PartRenderer* renderer) + { + this->renderer = renderer; + } }; namespace gl
--- a/src/gl/compiler.h Mon Jun 13 02:18:25 2022 +0300 +++ b/src/gl/compiler.h Tue Jun 14 17:55:50 2022 +0300 @@ -71,9 +71,8 @@ } shaderObjects[gl::NUM_ARRAY_CLASSES]; }; - void build( - ModelShaders* shaders, - Model *model, + void build(ModelShaders* shaders, + Model* model, const ColorTable& colorTable, DocumentManager* context, const RenderPreferences& preferences);
--- a/src/gl/gridprogram.cpp Mon Jun 13 02:18:25 2022 +0300 +++ b/src/gl/gridprogram.cpp Tue Jun 14 17:55:50 2022 +0300 @@ -68,7 +68,10 @@ void GridLayer::setGridMatrix(const glm::mat4& newGridMatrix) { - this->shader.setUniformMatrix("grid", newGridMatrix); + this->gridMatrix = newGridMatrix; + if (this->isInitialized) { + this->shader.setUniformMatrix("grid", newGridMatrix); + } } void GridLayer::setGridColor(const QColor& newGridColor) @@ -97,7 +100,7 @@ this->isInitialized = true; constexpr auto data = calcGridData<50>(); this->shader.setUniformVector("gridColor", this->gridColor); - this->setGridMatrix({{1, 0, 0, 0}, {0, 0, 1, 0}, {0, 1, 0, 0}, {0, 0, 0, 1}}); + this->setGridMatrix(this->gridMatrix); this->shader.bufferData(data.data(), data.size(), sizeof data[0]); }
--- a/src/gl/gridprogram.h Mon Jun 13 02:18:25 2022 +0300 +++ b/src/gl/gridprogram.h Tue Jun 14 17:55:50 2022 +0300 @@ -24,6 +24,7 @@ { BasicShader shader; glm::vec4 gridColor = {1.0f, 1.0f, 1.0f, 0.75f}; + glm::mat4 gridMatrix{1}; bool isInitialized = false; public: void setGridMatrix(const glm::mat4& newGridMatrix);
--- a/src/gl/partrenderer.cpp Mon Jun 13 02:18:25 2022 +0300 +++ b/src/gl/partrenderer.cpp Tue Jun 14 17:55:50 2022 +0300 @@ -18,6 +18,7 @@ #include <glm/ext/matrix_transform.hpp> #include <glm/ext/matrix_clip_space.hpp> +#include <QPainter> #include <GL/glu.h> #include <QMouseEvent> #include <QMessageBox> @@ -132,6 +133,10 @@ for (RenderLayer* layer : this->activeRenderLayers) { layer->paintGL(); } + QPainter painter{this}; + for (RenderLayer* layer : this->activeRenderLayers) { + layer->overpaint(&painter); + } } void PartRenderer::renderScene() @@ -292,6 +297,7 @@ { const bool left = event->buttons() & Qt::LeftButton; const QPoint move = event->pos() - this->lastMousePosition; + this->totalMouseMove += move.manhattanLength(); if (left and not move.isNull()) { // q_x is the rotation of the brick along the vertical y-axis, because turning the @@ -306,6 +312,27 @@ this->updateModelMatrix(); } this->lastMousePosition = event->pos(); + for (RenderLayer* layer : this->activeRenderLayers) { + layer->mouseMoved(event); + } + this->update(); +} + +void PartRenderer::mousePressEvent(QMouseEvent* event) +{ + this->totalMouseMove = 0; + this->lastMousePosition = event->pos(); +} + +void PartRenderer::mouseReleaseEvent(QMouseEvent* event) +{ + if (this->totalMouseMove < (2.0 / sqrt(2)) * 5.0) + { + for (RenderLayer* layer : this->activeRenderLayers) { + layer->mouseClick(event); + } + this->update(); + } } void PartRenderer::wheelEvent(QWheelEvent* event) @@ -320,6 +347,7 @@ void PartRenderer::addRenderLayer(RenderLayer* layer) { this->activeRenderLayers.push_back(layer); + layer->setRendererPointer(this); this->update(); } @@ -364,12 +392,17 @@ { const glm::vec3 projected = glm::project( point, - this->viewMatrix * glm::mat4_cast(this->modelQuaternion), + this->viewMatrix * this->modelMatrix, this->projectionMatrix, this->viewportVector); return toQPointF(glm::vec2{projected.x, this->height() - projected.y}); } +bool PartRenderer::isDark() const +{ + return luma(this->renderPreferences.backgroundColor) < 0.25; +} + Line<3> PartRenderer::cameraLine(const QPointF& point) const { const glm::vec3 p1 = this->unproject({point.x(), point.y(), 0}); @@ -386,7 +419,7 @@ { return glm::unProject( glm::vec3{win.x, this->height() - win.y, win.z}, - this->viewMatrix * glm::mat4_cast(this->modelQuaternion), + this->viewMatrix * this->modelMatrix, this->projectionMatrix, viewportVector); } @@ -445,3 +478,10 @@ { return this->highlighted; } + +void PartRenderer::setSelection(const QSet<ModelId>& selection) +{ + Q_ASSERT(not selection.contains({0})); + gl::setModelShaderSelectedObjects(&this->shaders, selection); + this->update(); +}
--- a/src/gl/partrenderer.h Mon Jun 13 02:18:25 2022 +0300 +++ b/src/gl/partrenderer.h Tue Jun 14 17:55:50 2022 +0300 @@ -6,9 +6,28 @@ #include "documentmanager.h" #include "types/boundingbox.h" -class PartRenderer : public QOpenGLWidget +class PartRenderer final : public QOpenGLWidget { Q_OBJECT + Model* const model; + DocumentManager* const documents; + const ColorTable& colorTable; + BoundingBox boundingBox; + gl::ModelShaders shaders; + ModelId highlighted = {0}; + glm::mat4 projectionMatrix; + glm::mat4 viewMatrix; + glm::mat4 modelMatrix; + glm::vec4 viewportVector; + glm::quat modelQuaternion; + QPoint lastMousePosition; + int totalMouseMove = 0; + gl::RenderPreferences renderPreferences; + double zoom = 1.0; + bool initialized = false; + bool needBuild = true; + std::vector<RenderLayer*> activeRenderLayers; + std::vector<RenderLayer*> inactiveRenderLayers; public: PartRenderer( Model* model, @@ -20,46 +39,31 @@ ModelId getHighlightedObject() const; void addRenderLayer(RenderLayer* layer); void setLayerEnabled(RenderLayer* layer, bool enabled); -protected: + std::optional<glm::vec3> screenToModelCoordinates(const QPointF& point, const Plane& plane) const; + QPointF modelToScreenCoordinates(const glm::vec3& point) const; + bool isDark() const; ModelId pick(QPoint where); - void initializeGL() override; - void resizeGL(int width, int height) override; - void paintGL() override; - void mouseMoveEvent(QMouseEvent* event) override; - void wheelEvent(QWheelEvent* event) override; - Model* const model; - DocumentManager* const documents; - const ColorTable& colorTable; - BoundingBox boundingBox; - gl::ModelShaders shaders; - ModelId highlighted = {0}; - std::optional<glm::vec3> screenToModelCoordinates(const QPointF &point, const Plane& plane) const; - QPointF modelToScreenCoordinates(const glm::vec3& point) const; - Line<3> cameraLine(const QPointF& point) const; - glm::vec3 unproject(const glm::vec3& win) const; - glm::mat4 projectionMatrix; - glm::mat4 viewMatrix; - glm::mat4 modelMatrix; - glm::vec4 viewportVector; - glm::quat modelQuaternion; - QPoint lastMousePosition; - gl::RenderPreferences renderPreferences; + void setSelection(const QSet<ModelId>& selectedIds); Q_SIGNALS: void projectionMatrixChanged(const glm::mat4& newMatrix); void modelMatrixChanged(const glm::mat4& newMatrix); void viewMatrixChanged(const glm::mat4& newMatrix); void renderPreferencesChanged(); private: + void initializeGL() override; + void resizeGL(int width, int height) override; + void paintGL() override; + void mouseMoveEvent(QMouseEvent* event) override; + void mousePressEvent(QMouseEvent* event) override; + void mouseReleaseEvent(QMouseEvent* event) override; + void wheelEvent(QWheelEvent* event) override; + Line<3> cameraLine(const QPointF& point) const; + glm::vec3 unproject(const glm::vec3& win) const; void setFragmentStyle(gl::FragmentStyle fragStyle); void renderScene(); void updateViewMatrix(); void updateModelMatrix(); Q_SLOT void build(); - double zoom = 1.0; - bool initialized = false; - bool needBuild = true; void renderVao(const gl::ArrayClass arrayClass); void checkForGLErrors(); - std::vector<RenderLayer*> activeRenderLayers; - std::vector<RenderLayer*> inactiveRenderLayers; };
--- a/src/main.cpp Mon Jun 13 02:18:25 2022 +0300 +++ b/src/main.cpp Tue Jun 14 17:55:50 2022 +0300 @@ -149,7 +149,8 @@ static ModelSubWindow* currentModelSubWindow(Ui_MainWindow* ui) { - return qobject_cast<ModelSubWindow*>(ui->mdiArea->activeSubWindow()); + auto* w = ui->mdiArea->activeSubWindow(); + return qobject_cast<ModelSubWindow*>(w); } static ModelData* currentModelData(Ui_MainWindow* ui, DocumentManager* documents) @@ -395,39 +396,39 @@ Model* model = documents.getModelById(modelId); if (model != nullptr) { ModelData* data = new ModelData(&documents); - data->tools = std::make_unique<EditTools>(model, colorTable); + data->tools = std::make_unique<EditTools>(); data->canvas = std::make_unique<PartRenderer>(model, &documents, colorTable); - data->itemSelectionModel = std::make_unique<QItemSelectionModel>(model); + data->itemSelectionModel = std::make_unique<QItemSelectionModel>(); + data->itemSelectionModel->setModel(model); data->axesLayer = std::make_unique<AxesLayer>(); + constexpr glm::mat4 XZ = {{1, 0, 0, 0}, {0, 0, 1, 0}, {0, 1, 0, 0}, {0, 0, 0, 1}}; data->gridLayer = std::make_unique<GridLayer>(); + data->gridLayer->setGridMatrix(XZ); + data->tools->setGridMatrix(XZ); data->model = model; data->canvas->addRenderLayer(data->axesLayer.get()); data->canvas->setLayerEnabled(data->axesLayer.get(), settings.drawAxes()); data->canvas->addRenderLayer(data->gridLayer.get()); + data->canvas->addRenderLayer(data->tools.get()); 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, - const QItemSelection& deselected) - { + QObject::connect( + data->itemSelectionModel.get(), + &QItemSelectionModel::selectionChanged, + [modelId, &documents]{ ModelData* data = findModelData(&documents, modelId); if (data != nullptr) { auto resolveIndex = [&data](const QModelIndex& index){ return data->model->idAt(index.row()); }; - auto resolve = [&resolveIndex](const QItemSelection& selection) - { - return fn::map<QSet<ModelId>>(selection.indexes(), resolveIndex); - }; - data->canvas->handleSelectionChange(resolve(selected), resolve(deselected)); + const auto selection = data->itemSelectionModel->selection(); + const auto indices = fn::map<QSet<ModelId>>(selection.indexes(), resolveIndex); + data->canvas->setSelection(indices); } }); -#endif data->canvas->setRenderPreferences(renderPreferences); QObject::connect( data->tools.get(), @@ -435,8 +436,27 @@ [&](const QString& newStatusText) { mainWindow.statusBar()->showMessage(newStatusText); }); + QObject::connect( + data->tools.get(), + &EditTools::select, + [modelId, &documents](const QSet<ModelId>& indices, bool retain) { + ModelData* data = findModelData(&documents, modelId); + if (data != nullptr) { + if (not retain) { + data->itemSelectionModel->clear(); + } + for (const ModelId id : indices) { + opt<int> index = data->model->find(id); + if (index.has_value()) { + const QModelIndex qindex = data->model->index(*index); + data->itemSelectionModel->select(qindex, QItemSelectionModel::Select); + } + } + } + }); const QFileInfo fileInfo{*documents.modelPath(modelId)}; - QMdiSubWindow* subWindow = ui.mdiArea->addSubWindow(data->canvas.get()); + ModelSubWindow* subWindow = new ModelSubWindow{modelId, ui.mdiArea}; + subWindow->setWidget(data->canvas.get()); subWindow->setWindowTitle(tabName(fileInfo)); subWindow->show(); }