2024-02-02 14:29:48 -05:00
|
|
|
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
|
|
|
#include "mapview.h"
|
|
|
|
|
|
|
|
#include <QThreadPool>
|
|
|
|
#include <QVBoxLayout>
|
|
|
|
|
2025-05-14 21:06:41 -04:00
|
|
|
#include "appstate.h"
|
2024-02-02 14:29:48 -05:00
|
|
|
#include "filecache.h"
|
2025-05-13 15:19:11 -04:00
|
|
|
#include "objectpass.h"
|
2024-02-02 14:29:48 -05:00
|
|
|
|
2025-05-13 16:57:37 -04:00
|
|
|
MapView::MapView(GameData *data, FileCache &cache, AppState *appState, QWidget *parent)
|
2024-02-02 14:29:48 -05:00
|
|
|
: QWidget(parent)
|
2025-05-14 21:06:41 -04:00
|
|
|
, m_data(data)
|
|
|
|
, m_cache(cache)
|
|
|
|
, m_appState(appState)
|
2024-02-02 14:29:48 -05:00
|
|
|
{
|
|
|
|
mdlPart = new MDLPart(data, cache);
|
|
|
|
mdlPart->enableFreemode();
|
2025-05-13 16:57:37 -04:00
|
|
|
connect(mdlPart, &MDLPart::initializeRender, this, [this, appState] {
|
|
|
|
mdlPart->manager()->addPass(new ObjectPass(mdlPart->manager(), appState));
|
2025-05-13 15:19:11 -04:00
|
|
|
});
|
2024-02-02 14:29:48 -05:00
|
|
|
|
|
|
|
auto layout = new QVBoxLayout();
|
|
|
|
layout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
layout->addWidget(mdlPart);
|
|
|
|
setLayout(layout);
|
2025-05-14 21:06:41 -04:00
|
|
|
|
2025-05-17 11:32:23 -04:00
|
|
|
connect(appState, &AppState::mapLoaded, this, &MapView::reloadMap);
|
|
|
|
connect(appState, &AppState::visibleLayerIdsChanged, this, &MapView::reloadMap);
|
2024-02-02 14:29:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
2025-05-14 21:06:41 -04:00
|
|
|
auto plateMdlFile = physis_gamedata_extract_file(m_data, mdlPathStd.c_str());
|
2024-02-02 14:29:48 -05:00
|
|
|
auto plateMdl = physis_mdl_parse(plateMdlFile);
|
2024-04-18 18:53:21 -04:00
|
|
|
if (plateMdl.p_ptr != nullptr) {
|
2024-05-27 13:15:50 -04:00
|
|
|
std::vector<physis_Material> materials;
|
|
|
|
for (uint32_t j = 0; j < plateMdl.num_material_names; j++) {
|
|
|
|
const char *material_name = plateMdl.material_names[j];
|
|
|
|
|
2025-05-17 13:10:46 -04:00
|
|
|
const auto matFile = m_cache.lookupFile(QLatin1String(material_name));
|
|
|
|
if (matFile.size > 0) {
|
|
|
|
auto mat = physis_material_parse(matFile);
|
|
|
|
materials.push_back(mat);
|
|
|
|
}
|
2024-05-27 13:15:50 -04:00
|
|
|
}
|
|
|
|
|
2024-04-18 18:53:21 -04:00
|
|
|
mdlPart->addModel(plateMdl,
|
|
|
|
false,
|
|
|
|
glm::vec3(terrain.plates[i].position[0], 0.0f, terrain.plates[i].position[1]),
|
|
|
|
QStringLiteral("terapart%1").arg(i),
|
2024-05-27 13:15:50 -04:00
|
|
|
materials,
|
2024-04-18 18:53:21 -04:00
|
|
|
0);
|
2025-05-17 09:48:33 -04:00
|
|
|
|
|
|
|
// We don't need this, and it will just take up memory
|
|
|
|
physis_mdl_free(&plateMdl);
|
|
|
|
|
|
|
|
physis_free_file(&plateMdlFile);
|
2024-04-18 18:53:21 -04:00
|
|
|
}
|
2024-02-02 14:29:48 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-05-17 11:32:23 -04:00
|
|
|
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());
|
2025-05-17 13:10:46 -04:00
|
|
|
if (tera_buffer.size > 0) {
|
|
|
|
auto tera = physis_parse_tera(tera_buffer);
|
|
|
|
addTerrain(bgPath, tera);
|
|
|
|
} else {
|
|
|
|
qWarning() << "Failed to load" << bgPathStd;
|
|
|
|
}
|
2025-05-17 11:32:23 -04:00
|
|
|
|
|
|
|
// add bg models
|
|
|
|
for (const auto &[name, lgb] : m_appState->lgbFiles) {
|
|
|
|
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];
|
|
|
|
|
2025-05-17 13:10:46 -04:00
|
|
|
const auto matFile = m_cache.lookupFile(QLatin1String(material_name));
|
|
|
|
if (matFile.size > 0) {
|
|
|
|
auto mat = physis_material_parse(matFile);
|
|
|
|
materials.push_back(mat);
|
|
|
|
}
|
2025-05-17 11:32:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2025-05-17 12:07:49 -04:00
|
|
|
} else {
|
|
|
|
qWarning() << "Failed to load" << assetPath;
|
2025-05-17 11:32:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-02 14:29:48 -05:00
|
|
|
#include "moc_mapview.cpp"
|