From 77f93c5224f3d72386f3bd457580986d7f176474 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Sat, 17 May 2025 11:32:23 -0400 Subject: [PATCH] Don't show all layers at once, allow selecting which ones to see You can now select which layers are currently visible in the object list view, and makes the performance *so much better* because it doesn't load everything by default. --- apps/mapeditor/include/appstate.h | 2 + apps/mapeditor/include/mapview.h | 2 + apps/mapeditor/include/objectlistmodel.h | 3 + apps/mapeditor/src/mapview.cpp | 154 ++++++++++++----------- apps/mapeditor/src/objectlistmodel.cpp | 40 +++++- apps/mapeditor/src/objectpass.cpp | 4 + 6 files changed, 127 insertions(+), 78 deletions(-) diff --git a/apps/mapeditor/include/appstate.h b/apps/mapeditor/include/appstate.h index 0f94774..7321cf9 100644 --- a/apps/mapeditor/include/appstate.h +++ b/apps/mapeditor/include/appstate.h @@ -14,7 +14,9 @@ public: QString basePath; std::vector> lgbFiles; + QList visibleLayerIds; Q_SIGNALS: void mapLoaded(); + void visibleLayerIdsChanged(); }; diff --git a/apps/mapeditor/include/mapview.h b/apps/mapeditor/include/mapview.h index 383eb2c..2f43008 100644 --- a/apps/mapeditor/include/mapview.h +++ b/apps/mapeditor/include/mapview.h @@ -25,6 +25,8 @@ public Q_SLOTS: void addTerrain(QString basePath, physis_Terrain terrain); private: + void reloadMap(); + MDLPart *mdlPart = nullptr; GameData *m_data; diff --git a/apps/mapeditor/include/objectlistmodel.h b/apps/mapeditor/include/objectlistmodel.h index 568c2f2..feaf629 100644 --- a/apps/mapeditor/include/objectlistmodel.h +++ b/apps/mapeditor/include/objectlistmodel.h @@ -23,6 +23,7 @@ struct TreeInformation { TreeInformation *parent = nullptr; int row = 0; QString name; + uint32_t id; std::vector children; }; @@ -42,6 +43,8 @@ public: QVariant data(const QModelIndex &index, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; private: void refresh(); diff --git a/apps/mapeditor/src/mapview.cpp b/apps/mapeditor/src/mapview.cpp index e1ce2ae..45d0cda 100644 --- a/apps/mapeditor/src/mapview.cpp +++ b/apps/mapeditor/src/mapview.cpp @@ -27,79 +27,8 @@ MapView::MapView(GameData *data, FileCache &cache, AppState *appState, QWidget * layout->addWidget(mdlPart); setLayout(layout); - connect(appState, &AppState::mapLoaded, this, [this] { - mdlPart->clear(); - - QString base2Path = m_appState->basePath.left(m_appState->basePath.lastIndexOf(QStringLiteral("/level/"))); - QString bgPath = QStringLiteral("bg/%1/bgplate/").arg(base2Path); - - std::string bgPathStd = bgPath.toStdString() + "terrain.tera"; - - auto tera_buffer = physis_gamedata_extract_file(m_data, bgPathStd.c_str()); - - auto tera = physis_parse_tera(tera_buffer); - addTerrain(bgPath, tera); - - // add bg models - for (const auto &[name, lgb] : m_appState->lgbFiles) { - // only load the bg models for now - if (name != QStringLiteral("bg")) { - continue; - } - - for (int i = 0; i < lgb.num_chunks; i++) { - const auto chunk = lgb.chunks[i]; - for (int j = 0; j < chunk.num_layers; j++) { - const auto layer = chunk.layers[j]; - for (int z = 0; z < layer.num_objects; z++) { - const auto object = layer.objects[z]; - - switch (object.data.tag) { - case physis_LayerEntry::Tag::BG: { - std::string assetPath = object.data.bg._0.asset_path; - if (!assetPath.empty()) { - if (!mdlPart->modelExists(QString::fromStdString(assetPath))) { - auto plateMdlFile = physis_gamedata_extract_file(m_data, assetPath.c_str()); - if (plateMdlFile.size == 0) { - continue; - } - - auto plateMdl = physis_mdl_parse(plateMdlFile); - if (plateMdl.p_ptr != nullptr) { - std::vector materials; - for (uint32_t j = 0; j < plateMdl.num_material_names; j++) { - const char *material_name = plateMdl.material_names[j]; - - auto mat = physis_material_parse(m_cache.lookupFile(QLatin1String(material_name))); - materials.push_back(mat); - } - - mdlPart->addModel( - plateMdl, - false, - glm::vec3(object.transform.translation[0], object.transform.translation[1], object.transform.translation[2]), - QString::fromStdString(assetPath), - materials, - 0); - - // We don't need this, and it will just take up memory - physis_mdl_free(&plateMdl); - } - - physis_free_file(&plateMdlFile); - } else { - mdlPart->addExistingModel( - QString::fromStdString(assetPath), - glm::vec3(object.transform.translation[0], object.transform.translation[1], object.transform.translation[2])); - } - } - } break; - } - } - } - } - } - }); + connect(appState, &AppState::mapLoaded, this, &MapView::reloadMap); + connect(appState, &AppState::visibleLayerIdsChanged, this, &MapView::reloadMap); } MDLPart &MapView::part() const @@ -139,4 +68,83 @@ void MapView::addTerrain(QString basePath, physis_Terrain terrain) } } +void MapView::reloadMap() +{ + mdlPart->clear(); + + QString base2Path = m_appState->basePath.left(m_appState->basePath.lastIndexOf(QStringLiteral("/level/"))); + QString bgPath = QStringLiteral("bg/%1/bgplate/").arg(base2Path); + + std::string bgPathStd = bgPath.toStdString() + "terrain.tera"; + + auto tera_buffer = physis_gamedata_extract_file(m_data, bgPathStd.c_str()); + + auto tera = physis_parse_tera(tera_buffer); + addTerrain(bgPath, tera); + + // add bg models + for (const auto &[name, lgb] : m_appState->lgbFiles) { + // only load the bg models for now + if (name != QStringLiteral("bg")) { + continue; + } + + for (int i = 0; i < lgb.num_chunks; i++) { + const auto chunk = lgb.chunks[i]; + for (int j = 0; j < chunk.num_layers; j++) { + const auto layer = chunk.layers[j]; + if (!m_appState->visibleLayerIds.contains(layer.id)) { + continue; + } + + for (int z = 0; z < layer.num_objects; z++) { + const auto object = layer.objects[z]; + + switch (object.data.tag) { + case physis_LayerEntry::Tag::BG: { + std::string assetPath = object.data.bg._0.asset_path; + if (!assetPath.empty()) { + if (!mdlPart->modelExists(QString::fromStdString(assetPath))) { + auto plateMdlFile = physis_gamedata_extract_file(m_data, assetPath.c_str()); + if (plateMdlFile.size == 0) { + continue; + } + + auto plateMdl = physis_mdl_parse(plateMdlFile); + if (plateMdl.p_ptr != nullptr) { + std::vector materials; + for (uint32_t j = 0; j < plateMdl.num_material_names; j++) { + const char *material_name = plateMdl.material_names[j]; + + auto mat = physis_material_parse(m_cache.lookupFile(QLatin1String(material_name))); + materials.push_back(mat); + } + + mdlPart->addModel( + plateMdl, + false, + glm::vec3(object.transform.translation[0], object.transform.translation[1], object.transform.translation[2]), + QString::fromStdString(assetPath), + materials, + 0); + + // We don't need this, and it will just take up memory + physis_mdl_free(&plateMdl); + } + + physis_free_file(&plateMdlFile); + } else { + mdlPart->addExistingModel( + QString::fromStdString(assetPath), + glm::vec3(object.transform.translation[0], object.transform.translation[1], object.transform.translation[2])); + } + } + } break; + } + } + } + } + } +} + #include "moc_mapview.cpp" diff --git a/apps/mapeditor/src/objectlistmodel.cpp b/apps/mapeditor/src/objectlistmodel.cpp index ea394b7..3b6d9cf 100644 --- a/apps/mapeditor/src/objectlistmodel.cpp +++ b/apps/mapeditor/src/objectlistmodel.cpp @@ -19,8 +19,6 @@ ObjectListModel::ObjectListModel(AppState *appState, QObject *parent) int ObjectListModel::rowCount(const QModelIndex &parent) const { TreeInformation *parentItem; - if (parent.column() > 0) - return 0; if (!parent.isValid()) parentItem = m_rootItem; @@ -33,7 +31,7 @@ int ObjectListModel::rowCount(const QModelIndex &parent) const int ObjectListModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent) - return 1; + return 2; } QModelIndex ObjectListModel::index(int row, int column, const QModelIndex &parent) const @@ -74,8 +72,14 @@ QVariant ObjectListModel::data(const QModelIndex &index, int role) const return {}; auto item = static_cast(index.internalPointer()); - if (role == Qt::DisplayRole) { - return item->name; + if (index.column() == 0) { + if (role == Qt::DisplayRole) { + return item->name; + } + } else if (index.column() == 1) { + if (role == Qt::CheckStateRole && item->type == TreeType::Layer) { + return m_appState->visibleLayerIds.contains(item->id) ? Qt::Checked : Qt::Unchecked; + } } return {}; @@ -86,12 +90,37 @@ QVariant ObjectListModel::headerData(int section, Qt::Orientation orientation, i if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { if (section == 0) { return i18nc("@title:column Object id", "Id"); + } else if (section == 1) { + return i18nc("@title:column If the layer is visible", "Visible"); } } return QAbstractItemModel::headerData(section, orientation, role); } +Qt::ItemFlags ObjectListModel::flags(const QModelIndex &index) const +{ + auto item = static_cast(index.internalPointer()); + if (index.column() == 1 && item->type == TreeType::Layer) + return QAbstractItemModel::flags(index) | Qt::ItemIsUserCheckable; + + return QAbstractItemModel::flags(index); +} + +bool ObjectListModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + auto item = static_cast(index.internalPointer()); + if (index.column() == 1 && item->type == TreeType::Layer) { + if (value.value() == Qt::Checked) { + m_appState->visibleLayerIds.push_back(item->id); + } else { + m_appState->visibleLayerIds.removeAll(item->id); + } + Q_EMIT m_appState->visibleLayerIdsChanged(); + } + return QAbstractItemModel::setData(index, value, role); +} + void ObjectListModel::refresh() { beginResetModel(); @@ -116,6 +145,7 @@ void ObjectListModel::refresh() layerItem->parent = fileItem; layerItem->name = i18n("Layer %1", j); // TODO: do display names if we have them layerItem->row = j; + layerItem->id = layer.id; fileItem->children.push_back(layerItem); for (int z = 0; z < layer.num_objects; z++) { diff --git a/apps/mapeditor/src/objectpass.cpp b/apps/mapeditor/src/objectpass.cpp index 1ed0ffc..d42a55f 100644 --- a/apps/mapeditor/src/objectpass.cpp +++ b/apps/mapeditor/src/objectpass.cpp @@ -37,6 +37,10 @@ void ObjectPass::render(VkCommandBuffer commandBuffer, Camera &camera) const auto chunk = lgb.chunks[i]; for (int j = 0; j < chunk.num_layers; j++) { const auto layer = chunk.layers[j]; + if (!m_appState->visibleLayerIds.contains(layer.id)) { + continue; + } + for (int z = 0; z < layer.num_objects; z++) { const auto object = layer.objects[z];