1
Fork 0
mirror of https://github.com/redstrate/Novus.git synced 2025-05-19 06:47:44 +00:00

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.
This commit is contained in:
Joshua Goins 2025-05-17 11:32:23 -04:00
parent da0240b3bf
commit 77f93c5224
6 changed files with 127 additions and 78 deletions

View file

@ -14,7 +14,9 @@ public:
QString basePath;
std::vector<std::pair<QString, physis_LayerGroup>> lgbFiles;
QList<uint32_t> visibleLayerIds;
Q_SIGNALS:
void mapLoaded();
void visibleLayerIdsChanged();
};

View file

@ -25,6 +25,8 @@ public Q_SLOTS:
void addTerrain(QString basePath, physis_Terrain terrain);
private:
void reloadMap();
MDLPart *mdlPart = nullptr;
GameData *m_data;

View file

@ -23,6 +23,7 @@ struct TreeInformation {
TreeInformation *parent = nullptr;
int row = 0;
QString name;
uint32_t id;
std::vector<TreeInformation *> 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();

View file

@ -27,7 +27,49 @@ MapView::MapView(GameData *data, FileCache &cache, AppState *appState, QWidget *
layout->addWidget(mdlPart);
setLayout(layout);
connect(appState, &AppState::mapLoaded, this, [this] {
connect(appState, &AppState::mapLoaded, this, &MapView::reloadMap);
connect(appState, &AppState::visibleLayerIdsChanged, this, &MapView::reloadMap);
}
MDLPart &MapView::part() const
{
return *mdlPart;
}
void MapView::addTerrain(QString basePath, physis_Terrain terrain)
{
for (int i = 0; i < terrain.num_plates; i++) {
QString mdlPath = QStringLiteral("%1%2").arg(basePath, QString::fromStdString(terrain.plates[i].filename));
std::string mdlPathStd = mdlPath.toStdString();
auto plateMdlFile = physis_gamedata_extract_file(m_data, mdlPathStd.c_str());
auto plateMdl = physis_mdl_parse(plateMdlFile);
if (plateMdl.p_ptr != nullptr) {
std::vector<physis_Material> 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(terrain.plates[i].position[0], 0.0f, terrain.plates[i].position[1]),
QStringLiteral("terapart%1").arg(i),
materials,
0);
// We don't need this, and it will just take up memory
physis_mdl_free(&plateMdl);
physis_free_file(&plateMdlFile);
}
}
}
void MapView::reloadMap()
{
mdlPart->clear();
QString base2Path = m_appState->basePath.left(m_appState->basePath.lastIndexOf(QStringLiteral("/level/")));
@ -51,6 +93,10 @@ MapView::MapView(GameData *data, FileCache &cache, AppState *appState, QWidget *
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];
@ -99,44 +145,6 @@ MapView::MapView(GameData *data, FileCache &cache, AppState *appState, QWidget *
}
}
}
});
}
MDLPart &MapView::part() const
{
return *mdlPart;
}
void MapView::addTerrain(QString basePath, physis_Terrain terrain)
{
for (int i = 0; i < terrain.num_plates; i++) {
QString mdlPath = QStringLiteral("%1%2").arg(basePath, QString::fromStdString(terrain.plates[i].filename));
std::string mdlPathStd = mdlPath.toStdString();
auto plateMdlFile = physis_gamedata_extract_file(m_data, mdlPathStd.c_str());
auto plateMdl = physis_mdl_parse(plateMdlFile);
if (plateMdl.p_ptr != nullptr) {
std::vector<physis_Material> 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(terrain.plates[i].position[0], 0.0f, terrain.plates[i].position[1]),
QStringLiteral("terapart%1").arg(i),
materials,
0);
// We don't need this, and it will just take up memory
physis_mdl_free(&plateMdl);
physis_free_file(&plateMdlFile);
}
}
}
#include "moc_mapview.cpp"

View file

@ -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,9 +72,15 @@ QVariant ObjectListModel::data(const QModelIndex &index, int role) const
return {};
auto item = static_cast<TreeInformation *>(index.internalPointer());
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<TreeInformation *>(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<TreeInformation *>(index.internalPointer());
if (index.column() == 1 && item->type == TreeType::Layer) {
if (value.value<Qt::CheckState>() == 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++) {

View file

@ -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];