From fbd70b6f0d758c50b907668b4bb7f805c01c172a Mon Sep 17 00:00:00 2001 From: T1ti <40864460+T1ti@users.noreply.github.com> Date: Thu, 18 Jul 2024 19:34:58 +0200 Subject: [PATCH] Implemented updating the doodad mapping/placement whenever an alphamap is modified, this means it should work with saving, and better than GEFixer --- src/noggit/Selection.cpp | 85 ++++++++----- src/noggit/World.cpp | 4 +- src/noggit/World.h | 2 +- src/noggit/rendering/TileRender.cpp | 8 ++ src/noggit/scripting/script_model.cpp | 2 +- src/noggit/texture_set.cpp | 122 ++++++++++++++++++- src/noggit/texture_set.hpp | 5 +- src/noggit/ui/GroundEffectsTool.hpp | 11 +- src/noggit/ui/ObjectEditor.cpp | 2 +- src/noggit/world_model_instances_storage.cpp | 11 +- src/noggit/world_model_instances_storage.hpp | 2 +- 11 files changed, 201 insertions(+), 53 deletions(-) diff --git a/src/noggit/Selection.cpp b/src/noggit/Selection.cpp index 41218695..ec6ea775 100755 --- a/src/noggit/Selection.cpp +++ b/src/noggit/Selection.cpp @@ -40,12 +40,14 @@ void selected_chunk_type::updateDetails(Noggit::Ui::detail_infos* detail_widget) <<"\n"; - // test compare active layer algorithm with blizzard. can reuse the same for saving + // test compare active layer algorithm with blizzard for the whole adt. can reuse the same for saving // TODO remove this int matching_count = 0; int not_matching_count = 0; int very_innacurate_count = 0; + int higher_count = 0; + int lower_count = 0; auto tile = chunk->mt; @@ -58,12 +60,17 @@ void selected_chunk_type::updateDetails(Noggit::Ui::detail_infos* detail_widget) { auto local_chunk = tile->getChunk(chunk_x, chunk_y); - auto blizzard_mapping = local_chunk->getTextureSet()->getDoodadMapping(); - auto blizzard_mapping_readable = local_chunk->getTextureSet()->getDoodadMappingReadable(); - - std::array test_doodadMapping{}; - std::array, 8> doodad_mapping_readable{}; + // auto blizzard_mapping = local_chunk->getTextureSet()->getDoodadMapping(); + // auto blizzard_mapping_readable = local_chunk->getTextureSet()->getDoodadMappingReadable(); + local_chunk->getTextureSet()->updateDoodadMapping(); + // test after creating new array + auto blizzard_mapping_readable = local_chunk->getTextureSet()->getDoodadMappingReadable(); + + + // test getting highest weight vs blizzard + std::array test_doodadMapping{}; + std::array, 8> test_doodad_mapping_readable{}; for (int x = 0; x < 8; x++) { for (int y = 0; y < 8; y++) @@ -74,34 +81,54 @@ void selected_chunk_type::updateDetails(Noggit::Ui::detail_infos* detail_widget) int max_layer_index = 0; for (int i = 1; i < weights.size(); i++) - if (weights[i] >= max) // (weights[i] >= max) ? superior layer seems to have priority + { + // in old azeroth maps superior layers seems to have higher priority + // error margin is ~4% in old azeroth without adjusted weight, 2% with + // error margin is < 0.5% in northrend without adjusting + + // float adjusted_weight = weights[i] * (1 + 0.05*i); // superior layer seems to have priority, adjust by 5% per layer + if (weights[i] >= max) + // if (std::floor(weights[i]) >= max) + // if (std::round(weights[i]) >= max) + // if (adjusted_weight >= max) // this works the best { max = weights[i]; max_layer_index = i; } + } unsigned int firstbit_pos = x * 2; - doodad_mapping_readable[y][x] = max_layer_index; + test_doodad_mapping_readable[y][x] = max_layer_index; // there might be a smarter way to do this - if (max_layer_index == 1) - { - test_doodadMapping[y] |= (1 << firstbit_pos); - } - else if (max_layer_index == 2) - { - test_doodadMapping[y] |= (1 << firstbit_pos + 1); - } - else if (max_layer_index == 3) - { - test_doodadMapping[y] |= (1 << firstbit_pos) | (1 << (firstbit_pos + 1)); - } - + // if (max_layer_index == 1) + // { + // test_doodadMapping[y] |= (1 << firstbit_pos); + // } + // else if (max_layer_index == 2) + // { + // test_doodadMapping[y] |= (1 << firstbit_pos + 1); + // } + // else if (max_layer_index == 3) + // { + // test_doodadMapping[y] |= (1 << firstbit_pos) | (1 << (firstbit_pos + 1)); + // } + + // the smarter way. + test_doodadMapping[y] |= ((max_layer_index & 3) << firstbit_pos); + // debug compare uint8_t blizzard_layer_id = blizzard_mapping_readable[y][x]; - //uint8_t blizzard_layer_id2 = blizzard_mapping_readable[x][y]; - uint8_t blizzard_layer_id3 = local_chunk->getTextureSet()->getDoodadActiveLayerIdAt(x, y); // make sure - bool test_doodads_enabled = local_chunk->getTextureSet()->getDoodadDisabledAt(x, y); + // + // uint8_t blizzard_layer_id3 = local_chunk->getTextureSet()->getDoodadActiveLayerIdAt(x, y); // make sure both work the same + // if (blizzard_layer_id != blizzard_layer_id3) + // throw; + // bool test_doodads_enabled = local_chunk->getTextureSet()->getDoodadDisabledAt(x, y); + + if (max_layer_index < blizzard_layer_id) + lower_count++; + if (max_layer_index > blizzard_layer_id) + higher_count++; if (max_layer_index != blizzard_layer_id) { @@ -125,18 +152,18 @@ void selected_chunk_type::updateDetails(Noggit::Ui::detail_infos* detail_widget) float debug_not_matching_percent = ((float)not_matching_count / (float)matching_count) * 100.f; - std::array weights = chunk->getTextureSet()->get_textures_weight_for_unit(unit_index.x, unit_index.y); + std::array unit_texture_weights = chunk->getTextureSet()->get_textures_weight_for_unit(unit_index.x, unit_index.y); if (chunk->getTextureSet()->num()) { select_info << "\n
DEBUG Chunk Unit texture weights:" - << "
0:" << weights[0] << "%"; + << "
0:" << unit_texture_weights[0] << "%"; } if (chunk->getTextureSet()->num()>1) - select_info << "
1:" << weights[1] << "%"; + select_info << "
1:" << unit_texture_weights[1] << "%"; if (chunk->getTextureSet()->num() > 2) - select_info << "
2:" << weights[2] << "%"; + select_info << "
2:" << unit_texture_weights[2] << "%"; if (chunk->getTextureSet()->num() > 3) - select_info << "
3:" << weights[3] << "%"; + select_info << "
3:" << unit_texture_weights[3] << "%"; // liquid details if the chunk has liquid data diff --git a/src/noggit/World.cpp b/src/noggit/World.cpp index b44109d7..3082efd3 100755 --- a/src/noggit/World.cpp +++ b/src/noggit/World.cpp @@ -677,7 +677,7 @@ void World::delete_selected_models() } } - _model_instance_storage.delete_instances(_current_selection); + _model_instance_storage.delete_instances(get_selected_objects()); need_model_updates = true; reset_selection(); } @@ -2039,7 +2039,7 @@ void World::reload_tile(TileIndex const& tile) mapIndex.reloadTile(tile); } -void World::deleteObjects(std::vector const& types) +void World::deleteObjects(std::vector const& types) { ZoneScoped; _model_instance_storage.delete_instances(types); diff --git a/src/noggit/World.h b/src/noggit/World.h index 283478ca..7c2078eb 100755 --- a/src/noggit/World.h +++ b/src/noggit/World.h @@ -373,7 +373,7 @@ public: void updateVertexCenter(); void clearVertexSelection(); - void deleteObjects(std::vector const& types); + void deleteObjects(std::vector const& types); float getMaxTileHeight(const TileIndex& tile); diff --git a/src/noggit/rendering/TileRender.cpp b/src/noggit/rendering/TileRender.cpp index d4837b15..fb07169c 100755 --- a/src/noggit/rendering/TileRender.cpp +++ b/src/noggit/rendering/TileRender.cpp @@ -154,6 +154,14 @@ void TileRender::draw (OpenGL::Scoped::use_program& mcnk_shader _split_drawcall = true; } } + // this isn't exactly rendering but... + if (flags & ChunkUpdateFlags::ALPHAMAP) + { + // recalculate doodad mapping. + chunk->getTextureSet()->updateDoodadMapping(); + + // setChunkGroundEffectActiveData(); + } if (!flags) continue; diff --git a/src/noggit/scripting/script_model.cpp b/src/noggit/scripting/script_model.cpp index 63188219..3b0ba22d 100755 --- a/src/noggit/scripting/script_model.cpp +++ b/src/noggit/scripting/script_model.cpp @@ -85,7 +85,7 @@ namespace Noggit void model::remove() { - std::vector type{_object}; + std::vector type{_object}; world()->deleteObjects(type); } diff --git a/src/noggit/texture_set.cpp b/src/noggit/texture_set.cpp index eccbd90c..6f2293e8 100755 --- a/src/noggit/texture_set.cpp +++ b/src/noggit/texture_set.cpp @@ -404,10 +404,10 @@ uint8_t const TextureSet::getDoodadActiveLayerIdAt(unsigned int x, unsigned int unsigned int firstbit_pos = x * 2; - bool first_bit = _doodadMapping[y] & (1 << firstbit_pos); - bool second_bit = _doodadMapping[y] & (1 << (firstbit_pos + 1) ); - - uint8_t layer_id = first_bit + second_bit * 2; + // bool first_bit = _doodadMapping[y] & (1 << firstbit_pos); + // bool second_bit = _doodadMapping[y] & (1 << (firstbit_pos + 1) ); + // uint8_t layer_id = first_bit | (second_bit << 1); // first_bit + second_bit * 2; + uint8_t layer_id = (_doodadMapping[y] >> firstbit_pos) & 0x03; return layer_id; } @@ -1395,6 +1395,120 @@ std::array TextureSet::get_textures_weight_for_unit(unsigned int unit_ return weights; } +void TextureSet::updateDoodadMapping() +{ + std::array new_doodad_mapping{}; + // std::array, 8> new_doodad_mapping{}; + // for (auto& row : new_doodad_mapping) { + // row.fill(nTextures - 1); + // } + + if (nTextures <= 1) + { + // 0 or 1 layer, we just use the 0 default + _doodadMapping = new_doodad_mapping; + return; + } + + // test comparison variables + int matching_count = 0; + int not_matching_count = 0; + int very_innacurate_count = 0; + int higher_count = 0; + int lower_count = 0; + auto blizzard_mapping_readable = getDoodadMappingReadable(); + bool debug_test = true; + + // 8x8 bits per unit + for (int unit_x = 0; unit_x < 8; unit_x++) + { + for (int unit_y = 0; unit_y < 8; unit_y++) + { + int layer_totals[4]{ 0,0,0,0 }; + + // 8x8 bits per unit + for (int x = 0; x < 8; x++) + { + for (int y = 0; y < 8; y++) + { + unsigned int base_alpha = 255; + + for (int alpha_layer = 0; alpha_layer < (nTextures - 1); ++alpha_layer) + { + auto alpha = static_cast(alphamaps[alpha_layer]->getAlpha((unit_y * 8 + y) * 64 + (unit_x * 8 + x))); + + layer_totals[alpha_layer+1] += alpha; + + base_alpha -= alpha; + } + layer_totals[0] += base_alpha; + } + } + + // int sum = layer_totals[0] + layer_totals[1] + layer_totals[2] + layer_totals[3]; + // std::array percent_weights = { total_layer_0 / sum * 100.f, + // total_layer_1 / sum * 100.f, + // total_layer_2 / sum * 100.f, + // total_layer_3 / sum * 100.f }; + + int max = layer_totals[0]; + int max_layer_index = 0; + + for (int i = 1; i < nTextures; i++) + { + // in old azeroth maps superior layers seems to have higher priority + // error margin is ~4% in old azeroth without adjusted weight, 2% with + // error margin is < 0.5% in northrend without adjusting + + float adjusted_weight = layer_totals[i] * (1 + 0.01*i); // superior layer seems to have priority, adjust by 1% per layer + // if (layer_totals[i] >= max) + // if (std::floor(weights[i]) >= max) + // if (std::round(weights[i]) >= max) + if (adjusted_weight >= max) // this with 5% works the best in old continents + { + max = layer_totals[i]; + max_layer_index = i; + } + } + unsigned int firstbit_pos = unit_x * 2; + new_doodad_mapping[unit_y] |= ((max_layer_index & 3) << firstbit_pos); + // new_chunk_mapping[y][x] = max_layer_index; + + // debug compare with original data + if (debug_test) + { + uint8_t blizzard_layer_id = blizzard_mapping_readable[unit_y][unit_x]; + uint8_t blizzard_layer_id2 = getDoodadActiveLayerIdAt(unit_x, unit_y); // make sure both work the same + if (blizzard_layer_id != blizzard_layer_id2) + throw; + // bool test_doodads_enabled = local_chunk->getTextureSet()->getDoodadDisabledAt(x, y); + + if (max_layer_index < blizzard_layer_id) + lower_count++; + if (max_layer_index > blizzard_layer_id) + higher_count++; + + if (max_layer_index != blizzard_layer_id) + { + int blizzard_effect_id = getEffectForLayer(blizzard_layer_id); + int found_effect_id = getEffectForLayer(max_layer_index); + not_matching_count++; + /* + float percent_innacuracy = ((layer_totals[max_layer_index] - layer_totals[blizzard_layer_id]) / ((static_cast(layer_totals[max_layer_index]) + layer_totals[blizzard_layer_id]) / 2)) * 100.f; + + if (percent_innacuracy > 15) + very_innacurate_count++;*/ + + } + else + matching_count++; + } + } + } + + _doodadMapping = new_doodad_mapping; +} + uint8_t TextureSet::sum_alpha(size_t offset) const { uint8_t sum = 0; diff --git a/src/noggit/texture_set.hpp b/src/noggit/texture_set.hpp index 96218a9e..68620f89 100755 --- a/src/noggit/texture_set.hpp +++ b/src/noggit/texture_set.hpp @@ -107,9 +107,8 @@ public: auto getDoodadMappingBase(void) -> std::uint16_t* { return _doodadMapping.data(); } std::array const& getDoodadMapping() { return _doodadMapping; } std::array, 8> const getDoodadMappingReadable(); // get array of readable values - uint8_t const getDoodadActiveLayerIdAt(unsigned int x, unsigned int y); // max is 8 + uint8_t const getDoodadActiveLayerIdAt(unsigned int unit_x, unsigned int unit_y); - // TODO x and Y are swapped std::array _doodadStencil; // doodads disabled if 1; WoD: may be an explicit MCDD chunk // this is actually uint1_t[8][8] (8*8 -> 1 bit each) auto getDoodadStencilBase(void) -> std::uint8_t* { return _doodadStencil.data(); } @@ -124,6 +123,8 @@ public: // get the weight of each texture in a chunk unit std::array get_textures_weight_for_unit(unsigned int unit_x, unsigned int unit_y); + void updateDoodadMapping(); + private: uint8_t sum_alpha(size_t offset) const; diff --git a/src/noggit/ui/GroundEffectsTool.hpp b/src/noggit/ui/GroundEffectsTool.hpp index b9e58c4e..796f8a7c 100644 --- a/src/noggit/ui/GroundEffectsTool.hpp +++ b/src/noggit/ui/GroundEffectsTool.hpp @@ -105,10 +105,13 @@ namespace Noggit //Close event triggers, hide event. void hideEvent(QHideEvent* event) override { - _map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_groundeffectid_overlay = false; - _map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_groundeffect_layerid_overlay = false; - _map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_noeffectdoodad_overlay = false; - _map_view->getWorld()->renderer()->markTerrainParamsUniformBlockDirty(); + if (_map_view->_world) + { + _map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_groundeffectid_overlay = false; + _map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_groundeffect_layerid_overlay = false; + _map_view->getWorld()->renderer()->getTerrainParamsUniformBlock()->draw_noeffectdoodad_overlay = false; + _map_view->getWorld()->renderer()->markTerrainParamsUniformBlockDirty(); + } QWidget::hideEvent(event); }; diff --git a/src/noggit/ui/ObjectEditor.cpp b/src/noggit/ui/ObjectEditor.cpp index 148247dc..75a855d6 100755 --- a/src/noggit/ui/ObjectEditor.cpp +++ b/src/noggit/ui/ObjectEditor.cpp @@ -649,7 +649,7 @@ namespace Noggit if (obj->which() == eMODEL) { - auto model_instance = static_cast(obj); + // auto model_instance = static_cast(obj); float scale(1.f); math::degrees::vec3 rotation(math::degrees(0)._, math::degrees(0)._, math::degrees(0)._); diff --git a/src/noggit/world_model_instances_storage.cpp b/src/noggit/world_model_instances_storage.cpp index d5d457c4..0a324d5b 100755 --- a/src/noggit/world_model_instances_storage.cpp +++ b/src/noggit/world_model_instances_storage.cpp @@ -116,7 +116,7 @@ namespace Noggit void world_model_instances_storage::delete_instances_from_tile(TileIndex const& tile) { // std::unique_lock const lock (_mutex); - std::vector instances_to_remove; + std::vector instances_to_remove; for (auto it = _m2s.begin(); it != _m2s.end(); ++it) { @@ -135,15 +135,10 @@ namespace Noggit delete_instances(instances_to_remove); } - void world_model_instances_storage::delete_instances(std::vector const& instances) + void world_model_instances_storage::delete_instances(std::vector const& instances) { - for (auto& it : instances) + for (auto& obj : instances) { - if (it.index() != eEntry_Object) - continue; - - auto obj = std::get(it); - // should be done in delete_instance if (NOGGIT_CUR_ACTION) NOGGIT_CUR_ACTION->registerObjectRemoved(obj); diff --git a/src/noggit/world_model_instances_storage.hpp b/src/noggit/world_model_instances_storage.hpp index 3607bf76..44429703 100755 --- a/src/noggit/world_model_instances_storage.hpp +++ b/src/noggit/world_model_instances_storage.hpp @@ -41,7 +41,7 @@ namespace Noggit std::optional get_instance(std::uint32_t uid, bool lock=true); void delete_instances_from_tile(TileIndex const& tile); - void delete_instances(std::vector const& instances); + void delete_instances(std::vector const& instances); void delete_instance(std::uint32_t uid); void unload_instance_and_remove_from_selection_if_necessary(std::uint32_t uid);