Thu, 03 Mar 2022 11:42:52 +0200
extract polygon cache out of Model
CMakeLists.txt | file | annotate | diff | comparison | revisions | |
src/document.cpp | file | annotate | diff | comparison | revisions | |
src/documentmanager.cpp | file | annotate | diff | comparison | revisions | |
src/documentmanager.h | file | annotate | diff | comparison | revisions | |
src/gl/compiler.cpp | file | annotate | diff | comparison | revisions | |
src/gl/compiler.h | file | annotate | diff | comparison | revisions | |
src/gl/partrenderer.cpp | file | annotate | diff | comparison | revisions | |
src/linetypes/object.h | file | annotate | diff | comparison | revisions | |
src/linetypes/subfilereference.cpp | file | annotate | diff | comparison | revisions | |
src/main.cpp | file | annotate | diff | comparison | revisions | |
src/model.cpp | file | annotate | diff | comparison | revisions | |
src/model.h | file | annotate | diff | comparison | revisions | |
src/polygoncache.cpp | file | annotate | diff | comparison | revisions | |
src/polygoncache.h | file | annotate | diff | comparison | revisions |
--- a/CMakeLists.txt Tue Nov 02 15:43:57 2021 +0200 +++ b/CMakeLists.txt Thu Mar 03 11:42:52 2022 +0200 @@ -25,7 +25,7 @@ source_group("3.2 Widgets" REGULAR_EXPRESSION "src/(ui|widgets)/.+\\.(cpp|h|ui)") source_group("3.1 Settings editor" REGULAR_EXPRESSION "src/settingseditor/.+\\.(cpp|h|ui)") source_group("3 User interface" REGULAR_EXPRESSION "src/(mainwindow|document|documentmanager|uiutilities)\\.(cpp|h|ui)") -source_group("2 Model handling" REGULAR_EXPRESSION "src/(model|modeleditcontext|libraries|colors|parser|vertexmap|edithistory)\\.(cpp|h|ui)") +source_group("2 Model handling" REGULAR_EXPRESSION "src/(model|modeleditcontext|libraries|colors|parser|vertexmap|edithistory|polygoncache)\\.(cpp|h|ui)") source_group("6 Editing tools" REGULAR_EXPRESSION "src/tools/.+\\.(cpp|h|ui)") set (LDFORGE_SOURCES @@ -42,6 +42,7 @@ src/model.cpp src/modeleditcontext.cpp src/parser.cpp + src/polygoncache.cpp src/uiutilities.cpp src/version.cpp src/vertexmap.cpp @@ -95,6 +96,7 @@ src/model.h src/modeleditcontext.h src/parser.h + src/polygoncache.h src/ring.h src/uiutilities.h src/utility.h
--- a/src/document.cpp Tue Nov 02 15:43:57 2021 +0200 +++ b/src/document.cpp Thu Mar 03 11:42:52 2022 +0200 @@ -57,7 +57,7 @@ QItemSelection selection; for (ldraw::id_t id : newSelection) { - QModelIndex index = this->model->lookup(id); + QModelIndex index = this->model->find(id); if (index != QModelIndex{}) { selection.select(index, index); @@ -70,7 +70,7 @@ connect(this->ui.listView->selectionModel(), &QItemSelectionModel::selectionChanged, [&](const QItemSelection& selected, const QItemSelection& deselected) { - auto resolveIndex = [this](const QModelIndex& index){ return this->model->resolve(index); }; + auto resolveIndex = [this](const QModelIndex& index){ return (*this->model)[index.row()]->id; }; auto resolve = [resolveIndex](const QItemSelection& selection) { return fn::map<QSet<ldraw::id_t>>(selection.indexes(), resolveIndex);
--- a/src/documentmanager.cpp Tue Nov 02 15:43:57 2021 +0200 +++ b/src/documentmanager.cpp Thu Mar 03 11:42:52 2022 +0200 @@ -45,8 +45,10 @@ const QString name = makeNewModelName(); this->openModels[modelId] = ModelInfo{ .model = std::make_unique<Model>(), + .id = modelId, .opentype = OpenType::ManuallyOpened, }; + this->makePolygonCacheForModel(modelId); return modelId; } @@ -141,7 +143,8 @@ if (file.error() == QFile::NoError) { const ModelId modelId{++this->modelIdCounter}; - this->openModels[modelId] = {std::move(newModel), path, openType}; + this->openModels[modelId] = {std::move(newModel), modelId, path, openType}; + this->makePolygonCacheForModel(modelId); result = modelId; } else @@ -299,6 +302,19 @@ return result; } +PolygonCache *DocumentManager::getPolygonCacheForModel(ModelId modelId) +{ + auto it = this->polygonCaches.find(modelId); + if (it != this->polygonCaches.end()) + { + return &it->second; + } + else + { + return nullptr; + } +} + /** * @brief Cleans up and erases models that are no longer required. */ @@ -311,6 +327,12 @@ and it->second.opentype == OpenType::AutomaticallyOpened and not this->isReferencedByAnything(it->first) ) { + // Remove its polygon cache + const auto polygonCache = this->polygonCaches.find(it->first); + if (polygonCache != this->polygonCaches.end()) + { + this->polygonCaches.erase(polygonCache); + } // Remove the model this->openModels.erase(it); // We need to start over now. It is possible that other models that previously @@ -345,6 +367,18 @@ return false; } +void DocumentManager::makePolygonCacheForModel(const ModelId modelId) +{ + Model* model = this->getModelById(modelId); + if (model != nullptr) + { + this->polygonCaches.emplace( + std::piecewise_construct, + std::forward_as_tuple(modelId), + std::forward_as_tuple(model)); + } +} + static QString findFile(QString referenceName, const QString& path, const LibraryManager& libraries) { // Try to find the file in the same place as the model itself
--- a/src/documentmanager.h Tue Nov 02 15:43:57 2021 +0200 +++ b/src/documentmanager.h Thu Mar 03 11:42:52 2022 +0200 @@ -19,6 +19,7 @@ #pragma once #include "libraries.h" #include "model.h" +#include "polygoncache.h" class DocumentManager : public QObject { @@ -55,10 +56,12 @@ QTextStream &errorStream); bool saveModel(const ModelId modelId, QTextStream& errors); std::optional<ModelId> findIdForModel(const Model* model) const; + PolygonCache* getPolygonCacheForModel(ModelId modelId); private: struct ModelInfo { std::unique_ptr<Model> model; + ModelId id; QString path; OpenType opentype; std::map<QString, ModelId> dependencies = {}; @@ -67,11 +70,13 @@ int modelIdCounter = 0; int untitledNameCounter = 0; std::map<ModelId, ModelInfo> openModels; + std::map<ModelId, PolygonCache> polygonCaches; void loadDependenciesForModel(const ModelId modelId, const QString& path, LoadDepedenciesBag& bag); void collectReferences(QSet<QString> &referenced, const QString& name, const Model* model); void updateDependencies(ModelInfo* model); void prune(); bool isReferencedByAnything(const ModelId modelId) const; + void makePolygonCacheForModel(const ModelId modelId); }; QString pathToName(const QFileInfo& path);
--- a/src/gl/compiler.cpp Tue Nov 02 15:43:57 2021 +0200 +++ b/src/gl/compiler.cpp Thu Mar 03 11:42:52 2022 +0200 @@ -125,8 +125,9 @@ } )"; -gl::Compiler::Compiler(const ldraw::ColorTable& colorTable, QObject* parent) : +gl::Compiler::Compiler(Model *model, const ldraw::ColorTable& colorTable, QObject* parent) : QObject{parent}, + model{model}, colorTable{colorTable} { } @@ -206,24 +207,32 @@ } } -void gl::Compiler::build(Model* model, DocumentManager* context, const gl::RenderPreferences& preferences) +void gl::Compiler::build(DocumentManager* context, const gl::RenderPreferences& preferences) { this->boundingBox = {}; std::vector<Vertex> vboData[gl::NUM_POLYGON_TYPES]; - const std::vector<gl::Polygon> polygons = model->getPolygons(context); - for (const gl::Polygon& polygon : polygons) - { - this->buildPolygon(polygon, vboData, preferences); - } - for (int arrayId = 0; arrayId < gl::NUM_POLYGON_TYPES; arrayId += 1) + std::optional<ModelId> modelId = context->findIdForModel(this->model); + if (modelId.has_value()) { - auto& buffer = this->glObjects[arrayId].buffer; - auto& vector = vboData[arrayId]; - this->storedVertexCounts[arrayId] = vector.size(); - this->glObjects[arrayId].cachedData = vector; // todo: get rid of this copy - buffer.bind(); - buffer.allocate(vector.data(), static_cast<int>(vector.size() * sizeof vector[0])); - buffer.release(); + PolygonCache* polygonBuilder = context->getPolygonCacheForModel(modelId.value()); + if (polygonBuilder != nullptr) + { + const std::vector<gl::Polygon> polygons = polygonBuilder->getPolygons(context); + for (const gl::Polygon& polygon : polygons) + { + this->buildPolygon(polygon, vboData, preferences); + } + for (int arrayId = 0; arrayId < gl::NUM_POLYGON_TYPES; arrayId += 1) + { + auto& buffer = this->glObjects[arrayId].buffer; + auto& vector = vboData[arrayId]; + this->storedVertexCounts[arrayId] = vector.size(); + this->glObjects[arrayId].cachedData = vector; // todo: get rid of this copy + buffer.bind(); + buffer.allocate(vector.data(), static_cast<int>(vector.size() * sizeof vector[0])); + buffer.release(); + } + } } }
--- a/src/gl/compiler.h Tue Nov 02 15:43:57 2021 +0200 +++ b/src/gl/compiler.h Thu Mar 03 11:42:52 2022 +0200 @@ -40,9 +40,9 @@ { Q_OBJECT public: - Compiler(const ldraw::ColorTable& colorTable, QObject* parent); + Compiler(Model* model, const ldraw::ColorTable& colorTable, QObject* parent); ~Compiler(); - void build(Model* model, DocumentManager* context, const RenderPreferences& preferences); + void build(DocumentManager* context, const RenderPreferences& preferences); std::size_t vertexCount(gl::ArrayClass arrayClass) const; QColor getColorForPolygon(const gl::Polygon& polygon, const RenderPreferences& preferences); glm::vec3 modelCenter() const; @@ -85,6 +85,7 @@ glm::int32 selected = 0; }; void buildPolygon(Polygon polygon, std::vector<Vertex>* vboData, const gl::RenderPreferences& preferences); + Model* const model; std::size_t storedVertexCounts[gl::NUM_POLYGON_TYPES] = {0}; bool initialized = false; BoundingBox boundingBox;
--- a/src/gl/partrenderer.cpp Tue Nov 02 15:43:57 2021 +0200 +++ b/src/gl/partrenderer.cpp Thu Mar 03 11:42:52 2022 +0200 @@ -38,7 +38,7 @@ model{model}, documents{documents}, colorTable{colorTable}, - compiler{new gl::Compiler{this->colorTable, this}} + compiler{new gl::Compiler{model, this->colorTable, this}} { this->setMouseTracking(true); connect(model, &Model::rowsInserted, [&]{ @@ -117,7 +117,7 @@ { if (this->needBuild) { - this->compiler->build(this->model, this->documents, this->renderPreferences); + this->compiler->build(this->documents, this->renderPreferences); this->needBuild = false; } this->checkForGLErrors();
--- a/src/linetypes/object.h Tue Nov 02 15:43:57 2021 +0200 +++ b/src/linetypes/object.h Thu Mar 03 11:42:52 2022 +0200 @@ -86,6 +86,20 @@ virtual void setProperty(SetPropertyResult* result, const PropertyKeyValue& pair); }; +/** + * @brief Tests whether the object is exactly of the specified type + * @tparam R Type of LDraw line type object to test for + * @param object Object to test + * @returns whether the type of the object specified by @c id is the same type as R. Returns false if it is a subclass. + */ +template<typename R> +bool isA(const ldraw::Object* object) +{ + const std::type_info& a = typeid(*object); + const std::type_info& b = typeid(R); + return a == b; +} + template<ldraw::Property property> ldraw::Object::SetPropertyResult ldraw::Object::setProperty(const ldraw::PropertyType<property>& value) {
--- a/src/linetypes/subfilereference.cpp Tue Nov 02 15:43:57 2021 +0200 +++ b/src/linetypes/subfilereference.cpp Thu Mar 03 11:42:52 2022 +0200 @@ -1,6 +1,7 @@ #include "subfilereference.h" #include "documentmanager.h" #include "invert.h" +#include "polygoncache.h" ldraw::SubfileReference::SubfileReference ( @@ -45,11 +46,20 @@ GetPolygonsContext* context ) const { - Model* referencedModel = this->resolve(context->modelId, context->documents); - if (referencedModel != nullptr) + Model* dependency = this->resolve(context->modelId, context->documents); + PolygonCache* referencedModelPolygonBuilder = nullptr; + if (dependency != nullptr) + { + const auto dependencyModelId = context->documents->findIdForModel(dependency); + if (dependencyModelId.has_value()) + { + referencedModelPolygonBuilder = context->documents->getPolygonCacheForModel(dependencyModelId.value()); + } + } + if (referencedModelPolygonBuilder != nullptr) { const bool needInverting = glm::determinant(this->transformation) < 0; - const std::vector<gl::Polygon> modelPolygons = referencedModel->getPolygons(context->documents); + const std::vector<gl::Polygon> modelPolygons = referencedModelPolygonBuilder->getPolygons(context->documents); polygons.reserve(polygons.size() + modelPolygons.size()); for (gl::Polygon polygon : modelPolygons) {
--- a/src/main.cpp Tue Nov 02 15:43:57 2021 +0200 +++ b/src/main.cpp Thu Mar 03 11:42:52 2022 +0200 @@ -29,14 +29,7 @@ QCoreApplication::setOrganizationDomain("hecknology.net"); ::qRegisterMetaTypeStreamOperators<Library>("Library"); ::qRegisterMetaTypeStreamOperators<Libraries>("Libraries"); - - glm::mat4 mat = glm::scale(glm::mat4{1}, {3, 3, 3}); - glm::vec4 x = {1,2,3,4}; - QApplication app{argc, argv}; - /* - QMessageBox::information(nullptr, "", QMetaType::typeName( qMetaTypeId<ldraw::Color>() )); - */ MainWindow mainwindow; mainwindow.show(); return app.exec();
--- a/src/model.cpp Tue Nov 02 15:43:57 2021 +0200 +++ b/src/model.cpp Thu Mar 03 11:42:52 2022 +0200 @@ -32,7 +32,6 @@ Model::Model(QObject *parent) : QAbstractListModel{parent} { - connect(this, &Model::dataChanged, [&](){ this->needRecache = true; }); } /** @@ -132,36 +131,11 @@ } /** - * @brief Gets a list of GL polygons that are used to represent this model. - * @details Will build polygons if polygons are outdated. - * @param documents Documents to use to resolve subfile references - * @return vector of GL polygons - */ -std::vector<gl::Polygon> Model::getPolygons(DocumentManager* documents) const -{ - if (this->needRecache) - { - this->cachedPolygons.clear(); - const std::optional<ModelId> modelId = documents->findIdForModel(this); - if (modelId.has_value()) - { - ldraw::GetPolygonsContext context{modelId.value(), documents}; - for (int i = 0; i < this->size(); i += 1) - { - this->getObjectPolygons(i, this->cachedPolygons, &context); - } - } - this->needRecache = false; - } - return this->cachedPolygons; -} - -/** * @brief Finds the position of the specified object in the model * @param id Object id to look for * @return model index */ -QModelIndex Model::lookup(ldraw::id_t id) const +QModelIndex Model::find(ldraw::id_t id) const { // FIXME: This linear search will probably cause performance issues for (std::size_t i = 0; i < this->body.size(); i += 1) @@ -179,7 +153,7 @@ * @param index Position of the object in the model * @return id */ -ldraw::id_t Model::resolve(const QModelIndex& index) const +ldraw::id_t Model::idAt(const QModelIndex& index) const { return this->objectAt(index)->id; } @@ -211,21 +185,6 @@ #endif /** - * @brief Gets the GL polygons of the object at the specified position in the model - * @param index Index of object in the model - * @param polygons_out Vector to add polygons into - * @param context Context to use to resolve subfile references - */ -void Model::getObjectPolygons( - const int index, - std::vector<gl::Polygon>& polygons_out, - ldraw::GetPolygonsContext* context) const -{ - const ldraw::Object* object = this->body[unsigned_cast(index)].get(); - object->getPolygons(polygons_out, context); -} - -/** * @brief Called by the editing context to signal to the model that editing is done. */ void Model::editFinished() @@ -239,7 +198,7 @@ */ void Model::objectModified(ldraw::id_t id) { - const QModelIndex index = this->lookup(id); + const QModelIndex index = this->find(id); Q_EMIT this->dataChanged(index, index); } @@ -250,10 +209,10 @@ void Model::append(ModelObjectPointer&& object) { const int position = static_cast<int>(this->body.size()); - Q_EMIT beginInsertRows({}, position, position); + Q_EMIT this->beginInsertRows({}, position, position); this->body.push_back(std::move(object)); - Q_EMIT endInsertRows(); - this->needRecache = true; + Q_EMIT this->endInsertRows(); + Q_EMIT this->objectAdded(position); } /** @@ -264,10 +223,11 @@ { if (position >= 0 and position < signed_cast(this->body.size())) { - Q_EMIT beginRemoveRows({}, position, position); + Q_EMIT this->beginRemoveRows({}, position, position); + const ldraw::id_t id = this->body[position]->id; this->body.erase(std::begin(this->body) + position); - Q_EMIT endRemoveRows(); - this->needRecache = true; + Q_EMIT this->endRemoveRows(); + Q_EMIT this->objectRemoved(id); } } @@ -303,29 +263,42 @@ } } +ldraw::Object* Model::operator[](int index) +{ + if (index >= 0 and index < this->size()) + { + return this->body[index].get(); + } + else + { + throw std::out_of_range{"index out of range"}; + } +} + /** * @brief Modifies the !LDRAW_ORG line so that it becomes unofficial */ -void Model::makeUnofficial() +void makeUnofficial(Model& model) { - if (this->body.size() >= 4) + if (model.size() >= 4) { - const ldraw::id_t id = this->body[3]->id; - if (this->isA<ldraw::MetaCommand>(id)) + const ldraw::Object* ldrawOrgLine = model[3]; + if (isA<ldraw::MetaCommand>(ldrawOrgLine)) { - const QString& body = this->body[3]->getProperty<ldraw::Property::Text>(); + const QString& body = ldrawOrgLine->getProperty<ldraw::Property::Text>(); if (body.startsWith("!LDRAW_ORG ") and not body.startsWith("!LDRAW_ORG Unofficial_")) { + // Add Unofficial_ to part type QStringList tokens = body.split(" "); tokens[1] = "Unofficial_" + tokens[1]; - // Remove the UPDATE tag + // Remove the UPDATE tag if it's there if (tokens.size() >= 4 && tokens[2] == "UPDATE") { tokens.removeAt(3); tokens.removeAt(2); } - EditContext editor = this->edit(); - editor.setObjectProperty<ldraw::Property::Text>(id, tokens.join(" ")); + Model::EditContext editor = model.edit(); + editor.setObjectProperty<ldraw::Property::Text>(ldrawOrgLine->id, tokens.join(" ")); } } }
--- a/src/model.h Tue Nov 02 15:43:57 2021 +0200 +++ b/src/model.h Thu Mar 03 11:42:52 2022 +0200 @@ -37,23 +37,18 @@ class EditContext; Model(QObject* parent = nullptr); Model(const Model&) = delete; + int size() const; ldraw::id_t at(int index) const; EditContext edit(); int rowCount(const QModelIndex&) const override; QVariant data(const QModelIndex& index, int role) const override; QVariant getHeaderProperty(const HeaderProperty property); - const QString& getName() const; QVariant getObjectProperty(const int index, const ldraw::Property property) const; template<ldraw::Property Property> ldraw::PropertyType<Property> getObjectProperty(const ldraw::id_t id) const; - std::vector<gl::Polygon> getPolygons(class DocumentManager* documents) const; - QModelIndex lookup(ldraw::id_t id) const; - ldraw::id_t resolve(const QModelIndex& index) const; - template<typename R> - ldraw::Id<R> checkType(ldraw::id_t id) const; - template<typename R> - bool isA(ldraw::id_t id) const; + QModelIndex find(ldraw::id_t id) const; + ldraw::id_t idAt(const QModelIndex& index) const; template<typename R> const R* get(ldraw::Id<R> id) const; template<typename R> @@ -67,10 +62,11 @@ template<typename R, typename Fn> void apply(Fn f) const; void save(QIODevice *device) const; - void makeUnofficial(); + ldraw::Object* operator[](int index); Q_SIGNALS: - void objectAdded(ldraw::id_t id, int position); - void objectModified(ldraw::id_t id, int position); + void objectAdded(int position); + void objectModified(int position); + void objectRemoved(ldraw::id_t id); private: using ModelObjectPointer = std::unique_ptr<ldraw::Object>; template<typename T, typename... Args> @@ -85,38 +81,19 @@ T* objectAt(ldraw::Id<T> id); template<typename T> const T* objectAt(ldraw::Id<T> id) const; - void getObjectPolygons( - const int index, - std::vector<gl::Polygon>& polygons_out, - ldraw::GetPolygonsContext* context) const; void editFinished(); void objectModified(ldraw::id_t id); bool modified = false; LDHeader header; std::vector<ModelObjectPointer> body; std::map<ldraw::id_t, ldraw::Object*> objectsById; - mutable std::vector<gl::Polygon> cachedPolygons; - mutable bool needRecache = true; /** * @brief Amount of model edit contexts active */ int editCounter = 0; }; -/** - * @brief Checks whether the id is exactly of the specified type - * @tparam R Type of LDraw line type object to test for - * @param id Id of object to test - * @returns whether the type of the object specified by @c id is the same type as R. Returns false if it is a subclass. - */ -template<typename R> -bool Model::isA(ldraw::id_t id) const -{ - const ldraw::Object* object = this->objectAt(this->lookup(id)); - const std::type_info& a = typeid(*object); - const std::type_info& b = typeid(R); - return a == b; -} +void makeUnofficial(Model& model); /** * @brief Calls the specified function to all matching objects in the model @@ -136,24 +113,6 @@ } } -/** - * \brief Checks type of object behind id - * Checks whether the specified id refers to an object of the specified type. - * \returns id casted to subclass if appropriate, null id otherwise - */ -template<typename R> -ldraw::Id<R> Model::checkType(ldraw::id_t id) const -{ - if (dynamic_cast<const R*>(this->objectAt(this->lookup(id))) != nullptr) - { - return ldraw::Id<R>{id.value}; - } - else - { - return ldraw::NULL_ID; - } -} - template<typename T, typename... Args> ldraw::Id<T> Model::append(Args&&... args) { @@ -162,9 +121,8 @@ this->body.push_back(std::make_unique<T>(args...)); ldraw::Object* pointer = this->body.back().get(); this->objectsById[pointer->id] = pointer; - Q_EMIT objectAdded(pointer->id, static_cast<int>(this->body.size() - 1)); + Q_EMIT objectAdded(static_cast<int>(this->body.size() - 1)); Q_EMIT endInsertRows(); - this->needRecache = true; return ldraw::Id<T>{pointer->id.value}; } @@ -175,9 +133,8 @@ this->body.insert(std::begin(this->body) + position, std::make_unique<T>(args...)); ldraw::Object* pointer = this->body[position].get(); this->objectsById[pointer->id] = pointer; - Q_EMIT objectAdded(pointer->id, static_cast<int>(position)); + Q_EMIT objectAdded(static_cast<int>(position)); Q_EMIT endInsertRows(); - this->needRecache = true; return ldraw::Id<T>{pointer->id.value}; } @@ -191,7 +148,7 @@ Model::Get2Result<R> Model::get2(const ldraw::Id<R> id) const { Get2Result<R> result; - result.index = this->lookup(id); + result.index = this->find(id); if (result.index.isValid()) { result.object = static_cast<const R*>(this->objectAt(result.index)); @@ -211,13 +168,13 @@ template<typename T> T* Model::objectAt(ldraw::Id<T> id) { - return static_cast<T*>(this->objectAt(this->lookup(id))); + return static_cast<T*>(this->objectAt(this->find(id))); } template<typename T> const T* Model::objectAt(ldraw::Id<T> id) const { - return static_cast<const T*>(this->objectAt(this->lookup(id))); + return static_cast<const T*>(this->objectAt(this->find(id))); } /**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/polygoncache.cpp Thu Mar 03 11:42:52 2022 +0200 @@ -0,0 +1,51 @@ +#include "polygoncache.h" +#include "documentmanager.h" + +PolygonCache::PolygonCache(Model *model) : + model{model} +{ + const auto mark = [this](){ this->needRecache = true; }; + connect(model, &Model::dataChanged, mark); + connect(model, &Model::objectAdded, mark); + connect(model, &Model::objectRemoved, mark); +} + +/** + * @brief Gets a list of GL polygons that are used to represent this model. + * @details Will build polygons if polygons are outdated. + * @param documents Documents to use to resolve subfile references + * @return vector of GL polygons + */ +std::vector<gl::Polygon> PolygonCache::getPolygons(DocumentManager* documents) +{ + if (this->needRecache) + { + this->cachedPolygons.clear(); + const std::optional<ModelId> modelId = documents->findIdForModel(this->model); + if (modelId.has_value()) + { + ldraw::GetPolygonsContext context{modelId.value(), documents}; + for (int i = 0; i < this->model->size(); i += 1) + { + this->getObjectPolygons(i, this->cachedPolygons, &context); + } + } + this->needRecache = false; + } + return this->cachedPolygons; +} + +/** + * @brief Gets the GL polygons of the object at the specified position in the model + * @param index Index of object in the model + * @param polygons_out Vector to add polygons into + * @param context Context to use to resolve subfile references + */ +void PolygonCache::getObjectPolygons( + const int index, + std::vector<gl::Polygon>& polygons_out, + ldraw::GetPolygonsContext* context) const +{ + const ldraw::Object* object = (*this->model)[unsigned_cast(index)]; + object->getPolygons(polygons_out, context); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/polygoncache.h Thu Mar 03 11:42:52 2022 +0200 @@ -0,0 +1,19 @@ +#pragma once +#include "main.h" +#include "model.h" + +class PolygonCache : QObject +{ + Q_OBJECT +public: + PolygonCache(Model* model); + std::vector<gl::Polygon> getPolygons(class DocumentManager* documents); +private: + void getObjectPolygons( + const int index, + std::vector<gl::Polygon>& polygons_out, + ldraw::GetPolygonsContext* context) const; + Model* const model; + std::vector<gl::Polygon> cachedPolygons; + bool needRecache = true; +};