Implemented updating the doodad mapping/placement whenever an alphamap is modified, this means it should work with saving, and better than GEFixer

This commit is contained in:
T1ti
2024-07-18 19:34:58 +02:00
parent b5c96babd9
commit fbd70b6f0d
11 changed files with 201 additions and 53 deletions

View File

@@ -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<std::uint16_t, 8> test_doodadMapping{};
std::array<std::array<std::uint8_t, 8>, 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<std::uint16_t, 8> test_doodadMapping{};
std::array<std::array<std::uint8_t, 8>, 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<float, 4> weights = chunk->getTextureSet()->get_textures_weight_for_unit(unit_index.x, unit_index.y);
std::array<float, 4> unit_texture_weights = chunk->getTextureSet()->get_textures_weight_for_unit(unit_index.x, unit_index.y);
if (chunk->getTextureSet()->num())
{
select_info << "\n<br><b>DEBUG Chunk Unit texture weights:</b>"
<< "<br>0:" << weights[0] << "%";
<< "<br>0:" << unit_texture_weights[0] << "%";
}
if (chunk->getTextureSet()->num()>1)
select_info << "<br>1:" << weights[1] << "%";
select_info << "<br>1:" << unit_texture_weights[1] << "%";
if (chunk->getTextureSet()->num() > 2)
select_info << "<br>2:" << weights[2] << "%";
select_info << "<br>2:" << unit_texture_weights[2] << "%";
if (chunk->getTextureSet()->num() > 3)
select_info << "<br>3:" << weights[3] << "%";
select_info << "<br>3:" << unit_texture_weights[3] << "%";
// liquid details if the chunk has liquid data

View File

@@ -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<selection_type> const& types)
void World::deleteObjects(std::vector<selected_object_type> const& types)
{
ZoneScoped;
_model_instance_storage.delete_instances(types);

View File

@@ -373,7 +373,7 @@ public:
void updateVertexCenter();
void clearVertexSelection();
void deleteObjects(std::vector<selection_type> const& types);
void deleteObjects(std::vector<selected_object_type> const& types);
float getMaxTileHeight(const TileIndex& tile);

View File

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

View File

@@ -85,7 +85,7 @@ namespace Noggit
void model::remove()
{
std::vector<selection_type> type{_object};
std::vector<SceneObject*> type{_object};
world()->deleteObjects(type);
}

View File

@@ -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<float, 4> TextureSet::get_textures_weight_for_unit(unsigned int unit_
return weights;
}
void TextureSet::updateDoodadMapping()
{
std::array<std::uint16_t, 8> new_doodad_mapping{};
// std::array<std::array<std::uint8_t, 8>, 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<int>(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<float, 4> 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<float>(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;

View File

@@ -107,9 +107,8 @@ public:
auto getDoodadMappingBase(void) -> std::uint16_t* { return _doodadMapping.data(); }
std::array<std::uint16_t, 8> const& getDoodadMapping() { return _doodadMapping; }
std::array<std::array<std::uint8_t, 8>, 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<std::uint8_t, 8> _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<float, 4> get_textures_weight_for_unit(unsigned int unit_x, unsigned int unit_y);
void updateDoodadMapping();
private:
uint8_t sum_alpha(size_t offset) const;

View File

@@ -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);
};

View File

@@ -649,7 +649,7 @@ namespace Noggit
if (obj->which() == eMODEL)
{
auto model_instance = static_cast<ModelInstance*>(obj);
// auto model_instance = static_cast<ModelInstance*>(obj);
float scale(1.f);
math::degrees::vec3 rotation(math::degrees(0)._, math::degrees(0)._, math::degrees(0)._);

View File

@@ -116,7 +116,7 @@ namespace Noggit
void world_model_instances_storage::delete_instances_from_tile(TileIndex const& tile)
{
// std::unique_lock<std::mutex> const lock (_mutex);
std::vector<selection_type> instances_to_remove;
std::vector<selected_object_type> 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<selection_type> const& instances)
void world_model_instances_storage::delete_instances(std::vector<selected_object_type> const& instances)
{
for (auto& it : instances)
for (auto& obj : instances)
{
if (it.index() != eEntry_Object)
continue;
auto obj = std::get<selected_object_type>(it);
// should be done in delete_instance
if (NOGGIT_CUR_ACTION)
NOGGIT_CUR_ACTION->registerObjectRemoved(obj);

View File

@@ -41,7 +41,7 @@ namespace Noggit
std::optional<selection_type> get_instance(std::uint32_t uid, bool lock=true);
void delete_instances_from_tile(TileIndex const& tile);
void delete_instances(std::vector<selection_type> const& instances);
void delete_instances(std::vector<selected_object_type> const& instances);
void delete_instance(std::uint32_t uid);
void unload_instance_and_remove_from_selection_if_necessary(std::uint32_t uid);