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:
@@ -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 = 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();
|
||||
|
||||
std::array<std::uint16_t, 8> test_doodadMapping{};
|
||||
std::array<std::array<std::uint8_t, 8>, 8> doodad_mapping_readable{};
|
||||
|
||||
// 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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace Noggit
|
||||
|
||||
void model::remove()
|
||||
{
|
||||
std::vector<selection_type> type{_object};
|
||||
std::vector<SceneObject*> type{_object};
|
||||
world()->deleteObjects(type);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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)._);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user