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:
parent
da0240b3bf
commit
77f93c5224
6 changed files with 127 additions and 78 deletions
|
@ -14,7 +14,9 @@ public:
|
||||||
|
|
||||||
QString basePath;
|
QString basePath;
|
||||||
std::vector<std::pair<QString, physis_LayerGroup>> lgbFiles;
|
std::vector<std::pair<QString, physis_LayerGroup>> lgbFiles;
|
||||||
|
QList<uint32_t> visibleLayerIds;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void mapLoaded();
|
void mapLoaded();
|
||||||
|
void visibleLayerIdsChanged();
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,6 +25,8 @@ public Q_SLOTS:
|
||||||
void addTerrain(QString basePath, physis_Terrain terrain);
|
void addTerrain(QString basePath, physis_Terrain terrain);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void reloadMap();
|
||||||
|
|
||||||
MDLPart *mdlPart = nullptr;
|
MDLPart *mdlPart = nullptr;
|
||||||
|
|
||||||
GameData *m_data;
|
GameData *m_data;
|
||||||
|
|
|
@ -23,6 +23,7 @@ struct TreeInformation {
|
||||||
TreeInformation *parent = nullptr;
|
TreeInformation *parent = nullptr;
|
||||||
int row = 0;
|
int row = 0;
|
||||||
QString name;
|
QString name;
|
||||||
|
uint32_t id;
|
||||||
|
|
||||||
std::vector<TreeInformation *> children;
|
std::vector<TreeInformation *> children;
|
||||||
};
|
};
|
||||||
|
@ -42,6 +43,8 @@ public:
|
||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role) const override;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, 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:
|
private:
|
||||||
void refresh();
|
void refresh();
|
||||||
|
|
|
@ -27,79 +27,8 @@ MapView::MapView(GameData *data, FileCache &cache, AppState *appState, QWidget *
|
||||||
layout->addWidget(mdlPart);
|
layout->addWidget(mdlPart);
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
connect(appState, &AppState::mapLoaded, this, [this] {
|
connect(appState, &AppState::mapLoaded, this, &MapView::reloadMap);
|
||||||
mdlPart->clear();
|
connect(appState, &AppState::visibleLayerIdsChanged, this, &MapView::reloadMap);
|
||||||
|
|
||||||
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<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(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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MDLPart &MapView::part() const
|
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<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(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"
|
#include "moc_mapview.cpp"
|
||||||
|
|
|
@ -19,8 +19,6 @@ ObjectListModel::ObjectListModel(AppState *appState, QObject *parent)
|
||||||
int ObjectListModel::rowCount(const QModelIndex &parent) const
|
int ObjectListModel::rowCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
TreeInformation *parentItem;
|
TreeInformation *parentItem;
|
||||||
if (parent.column() > 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!parent.isValid())
|
if (!parent.isValid())
|
||||||
parentItem = m_rootItem;
|
parentItem = m_rootItem;
|
||||||
|
@ -33,7 +31,7 @@ int ObjectListModel::rowCount(const QModelIndex &parent) const
|
||||||
int ObjectListModel::columnCount(const QModelIndex &parent) const
|
int ObjectListModel::columnCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(parent)
|
Q_UNUSED(parent)
|
||||||
return 1;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex ObjectListModel::index(int row, int column, const QModelIndex &parent) const
|
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 {};
|
return {};
|
||||||
|
|
||||||
auto item = static_cast<TreeInformation *>(index.internalPointer());
|
auto item = static_cast<TreeInformation *>(index.internalPointer());
|
||||||
if (role == Qt::DisplayRole) {
|
if (index.column() == 0) {
|
||||||
return item->name;
|
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 {};
|
return {};
|
||||||
|
@ -86,12 +90,37 @@ QVariant ObjectListModel::headerData(int section, Qt::Orientation orientation, i
|
||||||
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
|
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
|
||||||
if (section == 0) {
|
if (section == 0) {
|
||||||
return i18nc("@title:column Object id", "Id");
|
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);
|
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()
|
void ObjectListModel::refresh()
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
@ -116,6 +145,7 @@ void ObjectListModel::refresh()
|
||||||
layerItem->parent = fileItem;
|
layerItem->parent = fileItem;
|
||||||
layerItem->name = i18n("Layer %1", j); // TODO: do display names if we have them
|
layerItem->name = i18n("Layer %1", j); // TODO: do display names if we have them
|
||||||
layerItem->row = j;
|
layerItem->row = j;
|
||||||
|
layerItem->id = layer.id;
|
||||||
fileItem->children.push_back(layerItem);
|
fileItem->children.push_back(layerItem);
|
||||||
|
|
||||||
for (int z = 0; z < layer.num_objects; z++) {
|
for (int z = 0; z < layer.num_objects; z++) {
|
||||||
|
|
|
@ -37,6 +37,10 @@ void ObjectPass::render(VkCommandBuffer commandBuffer, Camera &camera)
|
||||||
const auto chunk = lgb.chunks[i];
|
const auto chunk = lgb.chunks[i];
|
||||||
for (int j = 0; j < chunk.num_layers; j++) {
|
for (int j = 0; j < chunk.num_layers; j++) {
|
||||||
const auto layer = chunk.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++) {
|
for (int z = 0; z < layer.num_objects; z++) {
|
||||||
const auto object = layer.objects[z];
|
const auto object = layer.objects[z];
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue