From 5db0e9ea49b7a3b0d2c792447e934fd136556ac9 Mon Sep 17 00:00:00 2001 From: T1ti <40864460+T1ti@users.noreply.github.com> Date: Sat, 25 May 2024 07:11:35 +0200 Subject: [PATCH] revamp image map imports and add progress bar for global operations --- src/noggit/MapTile.cpp | 8 +- src/noggit/MapView.cpp | 65 +++++-- src/noggit/World.cpp | 167 +++++++++++++----- src/noggit/World.h | 14 +- src/noggit/ui/TexturePicker.h | 2 + .../Nodes/World/Tile/TileSetAlphaLayer.cpp | 2 +- 6 files changed, 195 insertions(+), 63 deletions(-) diff --git a/src/noggit/MapTile.cpp b/src/noggit/MapTile.cpp index df6db85f..9a445b23 100755 --- a/src/noggit/MapTile.cpp +++ b/src/noggit/MapTile.cpp @@ -1223,7 +1223,7 @@ QImage MapTile::getAlphamapImage(std::string const& filename) } else // layer 1-3 { - auto alpha_layer = alphamaps->at(layer - 1).value(); + auto& alpha_layer = alphamaps->at(layer - 1).value(); int value = alpha_layer.getAlpha(64 * l + k); image.setPixelColor((i * 64) + k, (j * 64) + l, QColor(value, value, value, 255)); @@ -1441,11 +1441,13 @@ void MapTile::setAlphaImage(QImage const& baseimage, unsigned layer, bool cleanu } } + if (cleanup) + chunk->texture_set->eraseUnusedTextures(); + chunk->texture_set->markDirty(); chunk->texture_set->apply_alpha_changes(); - if (cleanup) - chunk->texture_set->eraseUnusedTextures(); + } } } diff --git a/src/noggit/MapView.cpp b/src/noggit/MapView.cpp index 19428f16..7f26cf2f 100755 --- a/src/noggit/MapView.cpp +++ b/src/noggit/MapView.cpp @@ -1545,6 +1545,11 @@ void MapView::setupAssistMenu() adt_import_params_layer->setRange(1, 3); adt_import_params_layout->addWidget(adt_import_params_layer); + QCheckBox* adt_import_params_cleanup_layers = new QCheckBox("Cleanup unused chunk layers", adt_import_params); + adt_import_params_cleanup_layers->setToolTip("Remove textures that have empty layers from chunks."); + adt_import_params_cleanup_layers->setChecked(false); + adt_import_params_layout->addWidget(adt_import_params_cleanup_layers); + QPushButton* adt_import_params_okay = new QPushButton("Okay", adt_import_params); adt_import_params_layout->addWidget(adt_import_params_okay); @@ -1590,7 +1595,7 @@ void MapView::setupAssistMenu() img.load(filepath, "PNG"); NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_TEXTURE); - _world->importADTAlphamap(_camera.position, img, adt_import_params_layer->value()); + _world->importADTAlphamap(_camera.position, img, adt_import_params_layer->value(), adt_import_params_cleanup_layers->isChecked()); NOGGIT_ACTION_MGR->endAction(); } @@ -1598,7 +1603,7 @@ void MapView::setupAssistMenu() ); ADD_ACTION_NS ( cur_adt_import_menu - , "Import alphamap" + , "Import alphamaps" , [=] { @@ -1606,7 +1611,7 @@ void MapView::setupAssistMenu() OpenGL::context::scoped_setter const _(::gl, context()); NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_TEXTURE); - _world->importADTAlphamap(_camera.position); + _world->importADTAlphamap(_camera.position, adt_import_params_cleanup_layers->isChecked()); NOGGIT_ACTION_MGR->endAction(); } ); @@ -1879,6 +1884,18 @@ void MapView::setupAssistMenu() } ); + ADD_ACTION_NS(assist_menu + , "Cleanup empty texture chunks" + , [this] + { + makeCurrent(); + OpenGL::context::scoped_setter const _(::gl, context()); + NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_TEXTURE); + _world->CleanupEmptyTexturesChunks(); + NOGGIT_ACTION_MGR->endAction(); + } + ); + assist_menu->addSeparator(); assist_menu->addAction(createTextSeparator("Global")); assist_menu->addSeparator(); @@ -1890,11 +1907,24 @@ void MapView::setupAssistMenu() ( makeCurrent(); OpenGL::context::scoped_setter const _ (::gl, context()); - _world->convert_alphamap(true); + if (_world->mapIndex.hasBigAlpha()) + { + QMessageBox::information(this + , "Noggit" + , "Map is already Big Alpha." + , QMessageBox::Ok + ); + } + else + { + QProgressDialog progress_dialog("Converting Alpha format...", "", 0, _world->mapIndex.getNumExistingTiles(), this); + progress_dialog.setWindowModality(Qt::WindowModal); + _world->convert_alphamap(&progress_dialog, true); + } ) - } ); + ADD_ACTION_NS ( assist_menu , "Map to old alpha" , [this] @@ -1903,7 +1933,19 @@ void MapView::setupAssistMenu() ( makeCurrent(); OpenGL::context::scoped_setter const _(::gl, context()); - _world->convert_alphamap(false); + if (!_world->mapIndex.hasBigAlpha()) + { + QMessageBox::information(this + , "Noggit" + , "Map is already Old Alpha." + , QMessageBox::Ok + ); + } + else + { + QProgressDialog progress_dialog("Converting Alpha format...", "", 0, _world->mapIndex.getNumExistingTiles(), this); + _world->convert_alphamap(&progress_dialog, false); + } ) } ); @@ -1993,14 +2035,14 @@ void MapView::setupAssistMenu() ( makeCurrent(); OpenGL::context::scoped_setter const _(::gl, context()); + QProgressDialog progress_dialog("Importing Alphamaps...", "Cancel", 0, _world->mapIndex.getNumExistingTiles(), this); + progress_dialog.setWindowModality(Qt::WindowModal); NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_TEXTURE); - _world->importAllADTsAlphamaps(); + _world->importAllADTsAlphamaps(&progress_dialog); NOGGIT_ACTION_MGR->endAction(); - ) } ); - ADD_ACTION_NS ( all_adts_import_menu , "Import heightmaps" , [=] @@ -2011,8 +2053,11 @@ void MapView::setupAssistMenu() ( makeCurrent(); OpenGL::context::scoped_setter const _(::gl, context()); + QProgressDialog progress_dialog("Importing Heightmaps...", "Cancel", 0, _world->mapIndex.getNumExistingTiles(), this); + progress_dialog.setWindowModality(Qt::WindowModal); NOGGIT_ACTION_MGR->beginAction(this, Noggit::ActionFlags::eCHUNKS_TERRAIN); - _world->importAllADTsHeightmaps(heightmap_import_min->value(), heightmap_import_max->value(), adt_import_height_params_mode->currentIndex(), adt_import_height_tiled_edges->isChecked()); + _world->importAllADTsHeightmaps(&progress_dialog, heightmap_import_max->value(), heightmap_import_min->value(), + adt_import_height_params_mode->currentIndex(), adt_import_height_tiled_edges->isChecked()); NOGGIT_ACTION_MGR->endAction(); ) diff --git a/src/noggit/World.cpp b/src/noggit/World.cpp index 864ffffc..4cbe1a81 100755 --- a/src/noggit/World.cpp +++ b/src/noggit/World.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -1612,17 +1613,48 @@ bool World::sprayTexture(glm::vec3 const& pos, Brush *brush, float strength, flo return succ; } -bool World::replaceTexture(glm::vec3 const& pos, float radius, scoped_blp_texture_reference const& old_texture, scoped_blp_texture_reference new_texture, bool entire_chunk) +bool World::replaceTexture(glm::vec3 const& pos, float radius, scoped_blp_texture_reference const& old_texture, scoped_blp_texture_reference new_texture, bool entire_chunk, bool entire_tile) { ZoneScoped; - return for_all_chunks_in_range - ( pos, radius - , [&](MapChunk* chunk) + + if (entire_tile) + { + bool changed(false); + + for (MapTile* tile : mapIndex.tiles_in_range(pos, radius)) { - NOGGIT_CUR_ACTION->registerChunkTextureChange(chunk); - return chunk->replaceTexture(pos, radius, old_texture, new_texture, entire_chunk); + if (!tile->finishedLoading()) + { + continue; + } + + for (int i = 0; i < 16; ++i) + { + for (int j = 0; j < 16; ++j) + { + MapChunk* chunk = tile->getChunk(i, j); + NOGGIT_CUR_ACTION->registerChunkTextureChange(chunk); + if (chunk->replaceTexture(pos, radius, old_texture, new_texture, true)) + { + changed = true; + mapIndex.setChanged(tile); + } + } + } } - ); + return changed; + } + else + { + return for_all_chunks_in_range + ( pos, radius + , [&](MapChunk* chunk) + { + NOGGIT_CUR_ACTION->registerChunkTextureChange(chunk); + return chunk->replaceTexture(pos, radius, old_texture, new_texture, entire_chunk); + } + ); + } } void World::eraseTextures(glm::vec3 const& pos) @@ -1690,7 +1722,7 @@ void World::loadAllTiles() } } -void World::convert_alphamap(bool to_big_alpha) +void World::convert_alphamap(QProgressDialog* progress_dialog, bool to_big_alpha) { ZoneScoped; @@ -1699,10 +1731,13 @@ void World::convert_alphamap(bool to_big_alpha) return; } + + int count = 0; for (size_t z = 0; z < 64; z++) { for (size_t x = 0; x < 64; x++) { + // not cancellable. TileIndex tile(x, z); bool unload = !mapIndex.tileLoaded(tile) && !mapIndex.tileAwaitingLoading(tile); @@ -1721,10 +1756,11 @@ void World::convert_alphamap(bool to_big_alpha) { mapIndex.unloadTile(tile); } + count++; + progress_dialog->setValue(count); } } } - mapIndex.convert_alphamap(to_big_alpha); mapIndex.save(); } @@ -1890,10 +1926,10 @@ ModelInstance* World::addM2AndGetInstance ( BlizzardArchive::Listfile::FileKey c std::uint32_t uid = _model_instance_storage.add_model_instance(std::move(model_instance), true); - auto instance = _model_instance_storage.get_model_instance(uid).value(); + auto instance = _model_instance_storage.get_model_instance(uid); // .value(); // _models_by_filename[file_key.filepath()].push_back(instance); - return instance; + return instance.value(); } void World::addWMO ( BlizzardArchive::Listfile::FileKey const& file_key @@ -1933,7 +1969,9 @@ WMOInstance* World::addWMOAndGetInstance ( BlizzardArchive::Listfile::FileKey co std::uint32_t uid = _model_instance_storage.add_wmo_instance(std::move(wmo_instance), true); - return _model_instance_storage.get_wmo_instance(uid).value(); + auto instance = _model_instance_storage.get_wmo_instance(uid); + + return instance.value(); } @@ -2042,7 +2080,7 @@ void World::wait_for_all_tile_updates() _tile_update_queue.wait_for_all_update(); } -unsigned int World::getMapID() +unsigned int World::getMapID() const { ZoneScoped; return mapIndex._map_id; @@ -2189,7 +2227,7 @@ void World::exportADTVertexColorMap(glm::vec3 const& pos) ); } -void World::importADTAlphamap(glm::vec3 const& pos, QImage const& image, unsigned layer) +void World::importADTAlphamap(glm::vec3 const& pos, QImage const& image, unsigned layer, bool cleanup) { ZoneScoped; for_all_chunks_on_tile(pos, [](MapChunk* chunk) @@ -2204,7 +2242,7 @@ void World::importADTAlphamap(glm::vec3 const& pos, QImage const& image, unsigne for_tile_at ( pos , [&] (MapTile* tile) { - tile->setAlphaImage(scaled, layer); + tile->setAlphaImage(scaled, layer, cleanup); } ); @@ -2214,14 +2252,14 @@ void World::importADTAlphamap(glm::vec3 const& pos, QImage const& image, unsigne for_tile_at ( pos , [&] (MapTile* tile) { - tile->setAlphaImage(image, layer); + tile->setAlphaImage(image, layer, cleanup); } ); } } -void World::importADTAlphamap(glm::vec3 const& pos) +void World::importADTAlphamap(glm::vec3 const& pos, bool cleanup) { ZoneScoped; for_all_chunks_on_tile(pos, [](MapChunk* chunk) @@ -2253,7 +2291,7 @@ void World::importADTAlphamap(glm::vec3 const& pos) if (img.width() != 1024 || img.height() != 1024) img = img.scaled(1024, 1024, Qt::AspectRatioMode::IgnoreAspectRatio); - tile->setAlphaImage(img, i); + tile->setAlphaImage(img, i, true); } } @@ -2620,7 +2658,7 @@ void World::setWaterType(const TileIndex& pos, int type, int layer) ); } -int World::getWaterType(const TileIndex& tile, int layer) +int World::getWaterType(const TileIndex& tile, int layer) const { ZoneScoped; if (mapIndex.tileLoaded(tile)) @@ -2646,6 +2684,36 @@ void World::autoGenWaterTrans(const TileIndex& pos, float factor) }); } +void World::CleanupEmptyTexturesChunks() +{ + ZoneScoped; + for (MapTile* tile : mapIndex.loaded_tiles()) + { + bool tileChanged = false; + + for (unsigned ty = 0; ty < 16; ty++) + { + for (unsigned tx = 0; tx < 16; tx++) + { + MapChunk* chunk = tile->getChunk(tx, ty); + + TextureSet* texture_set = chunk->getTextureSet(); + + bool changed = texture_set->eraseUnusedTextures(); + + if (changed) + { + NOGGIT_CUR_ACTION->registerChunkTextureChange(chunk); + tileChanged = true; + } + } + } + if (tileChanged) + { + mapIndex.setChanged(tile); + } + } +} void World::fixAllGaps() { @@ -2728,7 +2796,7 @@ void World::fixAllGaps() } } -bool World::isUnderMap(glm::vec3 const& pos) +bool World::isUnderMap(glm::vec3 const& pos) const { ZoneScoped; TileIndex const tile (pos); @@ -3235,66 +3303,74 @@ void World::exportAllADTsVertexColorMap() } } -void World::importAllADTsAlphamaps() +void World::importAllADTsAlphamaps(QProgressDialog* progress_dialog) { + bool clean_up = false; ZoneScoped; QString path = QString(Noggit::Project::CurrentProject::get()->ProjectPath.c_str()); if (!(path.endsWith('\\') || path.endsWith('/'))) { path += "/"; } - + int count = 0; for (size_t z = 0; z < 64; z++) { for (size_t x = 0; x < 64; x++) { + if (progress_dialog->wasCanceled()) + return; + TileIndex tile(x, z); bool unload = !mapIndex.tileLoaded(tile) && !mapIndex.tileAwaitingLoading(tile); MapTile* mTile = mapIndex.loadTile(tile); - + if (mTile) { mTile->wait_until_loaded(); - + for (int i = 1; i < 4; ++i) { QString filename = path + "/world/maps/" + basename.c_str() + "/" + basename.c_str() + "_" + std::to_string(mTile->index.x).c_str() + "_" + std::to_string(mTile->index.z).c_str() + "_layer" + std::to_string(i).c_str() + ".png"; - + if(!QFileInfo::exists(filename)) continue; - + QImage img; img.load(filename, "PNG"); - + if (img.width() != 1024 || img.height() != 1024) { QImage scaled = img.scaled(1024, 1024, Qt::IgnoreAspectRatio); - mTile->setAlphaImage(scaled, i); + mTile->setAlphaImage(scaled, i, clean_up); } else { - mTile->setAlphaImage(img, i); + mTile->setAlphaImage(img, i, clean_up); } - + } - + mTile->saveTile(this); mapIndex.markOnDisc (tile, true); mapIndex.unsetChanged(tile); - + if (unload) { mapIndex.unloadTile(tile); } + + count++; + progress_dialog->setValue(count); } + } } } -void World::importAllADTsHeightmaps(float min_height, float max_height, unsigned int mode, bool tiledEdges) +void World::importAllADTsHeightmaps(QProgressDialog* progress_dialog, float min_height, float max_height, unsigned mode, bool tiledEdges) { ZoneScoped; QString path = QString(Noggit::Project::CurrentProject::get()->ProjectPath.c_str()); @@ -3303,29 +3379,32 @@ void World::importAllADTsHeightmaps(float min_height, float max_height, unsigned path += "/"; } + int count = 0; for (size_t z = 0; z < 64; z++) { for (size_t x = 0; x < 64; x++) { + if (progress_dialog->wasCanceled()) + return; TileIndex tile(x, z); bool unload = !mapIndex.tileLoaded(tile) && !mapIndex.tileAwaitingLoading(tile); MapTile* mTile = mapIndex.loadTile(tile); - + if (mTile) { mTile->wait_until_loaded(); - + QString filename = path + "/world/maps/" + basename.c_str() + "/" + basename.c_str() + "_" + std::to_string(mTile->index.x).c_str() + "_" + std::to_string(mTile->index.z).c_str() + "_height.png"; - - if(!QFileInfo::exists(filename)) - continue; - + + if (!QFileInfo::exists(filename)) + continue; + QImage img; img.load(filename, "PNG"); - + size_t desiredSize = tiledEdges ? 256 : 257; if (img.width() != desiredSize || img.height() != desiredSize) { @@ -3336,21 +3415,23 @@ void World::importAllADTsHeightmaps(float min_height, float max_height, unsigned { mTile->setHeightmapImage(img, min_height, max_height, mode, tiledEdges); } - + mTile->saveTile(this); mapIndex.markOnDisc (tile, true); mapIndex.unsetChanged(tile); - + if (unload) { mapIndex.unloadTile(tile); } + count++; + progress_dialog->setValue(count); } } } } -void World::importAllADTVertexColorMaps(unsigned int mode, bool tiledEdges) +void World::importAllADTVertexColorMaps(unsigned mode, bool tiledEdges) { ZoneScoped; QString path = QString(Noggit::Project::CurrentProject::get()->ProjectPath.c_str()); diff --git a/src/noggit/World.h b/src/noggit/World.h index d75f736d..c580a7c9 100755 --- a/src/noggit/World.h +++ b/src/noggit/World.h @@ -31,6 +31,7 @@ #include #include #include +#include namespace Noggit { @@ -262,16 +263,16 @@ public: void exportAllADTsHeightmap(); void exportAllADTsVertexColorMap(); - void importADTAlphamap(glm::vec3 const& pos, QImage const& image, unsigned layer); - void importADTAlphamap(glm::vec3 const& pos); + void importADTAlphamap(glm::vec3 const& pos, QImage const& image, unsigned layer, bool cleanup); + void importADTAlphamap(glm::vec3 const& pos, bool cleanup); void importADTHeightmap(glm::vec3 const& pos, QImage const& image, float min_height, float max_height, unsigned mode, bool tiledEdges); void importADTHeightmap(glm::vec3 const& pos, float min_height, float max_height, unsigned mode, bool tiledEdges); void importADTWatermap(glm::vec3 const& pos, QImage const& image, float min_height, float max_height, unsigned mode, bool tiledEdges); void importADTVertexColorMap(glm::vec3 const& pos, int mode, bool tiledEdges); void importADTVertexColorMap(glm::vec3 const& pos, QImage const& image, int mode, bool tiledEdges); - void importAllADTsAlphamaps(); - void importAllADTsHeightmaps(float min_height, float max_height, unsigned mode, bool tiledEdges); + void importAllADTsAlphamaps(QProgressDialog* progress_dialog); + void importAllADTsHeightmaps(QProgressDialog* progress_dialog, float min_height, float max_height, unsigned mode, bool tiledEdges); void importAllADTVertexColorMaps(unsigned mode, bool tiledEdges); void ensureAllTilesetsADT(glm::vec3 const& pos); @@ -351,13 +352,14 @@ public: ); void CropWaterADT(const TileIndex& pos); void setWaterType(const TileIndex& pos, int type, int layer); - int getWaterType(const TileIndex& tile, int layer); + int getWaterType(const TileIndex& tile, int layer) const; void autoGenWaterTrans(const TileIndex&, float factor); void fixAllGaps(); - void convert_alphamap(bool to_big_alpha); + void CleanupEmptyTexturesChunks(); + void convert_alphamap(QProgressDialog* progress_dialog, bool to_big_alpha); bool deselectVertices(glm::vec3 const& pos, float radius); void selectVertices(glm::vec3 const& pos, float radius); diff --git a/src/noggit/ui/TexturePicker.h b/src/noggit/ui/TexturePicker.h index f43de268..6615537c 100755 --- a/src/noggit/ui/TexturePicker.h +++ b/src/noggit/ui/TexturePicker.h @@ -34,9 +34,11 @@ namespace Noggit void update(bool set_changed = true); QGridLayout* layout; + bool _display_alphamaps = true; std::vector _labels; std::vector _textures; + std::vector _alphamap_preview_labels; MapChunk* _chunk; current_texture* _main_texture_window; diff --git a/src/noggit/ui/tools/NodeEditor/Nodes/World/Tile/TileSetAlphaLayer.cpp b/src/noggit/ui/tools/NodeEditor/Nodes/World/Tile/TileSetAlphaLayer.cpp index 0ef64013..defbc001 100755 --- a/src/noggit/ui/tools/NodeEditor/Nodes/World/Tile/TileSetAlphaLayer.cpp +++ b/src/noggit/ui/tools/NodeEditor/Nodes/World/Tile/TileSetAlphaLayer.cpp @@ -56,7 +56,7 @@ void TileSetAlphaLayerNode::compute() image_to_process = &scaled; } - tile->setAlphaImage(*image_to_process, layer); + tile->setAlphaImage(*image_to_process, layer, true); _out_ports[0].out_value = std::make_shared(true); _node->onDataUpdated(0);