397 lines
10 KiB
C++
Executable File
397 lines
10 KiB
C++
Executable File
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
|
|
|
#include <noggit/world_model_instances_storage.hpp>
|
|
#include <noggit/World.h>
|
|
#include <noggit/ActionManager.hpp>
|
|
#include <noggit/Action.hpp>
|
|
|
|
namespace Noggit
|
|
{
|
|
world_model_instances_storage::world_model_instances_storage(World* world)
|
|
: _world(world)
|
|
{
|
|
|
|
}
|
|
|
|
std::uint32_t world_model_instances_storage::add_model_instance(ModelInstance instance, bool from_reloading)
|
|
{
|
|
std::uint32_t uid = instance.uid;
|
|
std::uint32_t uid_after;
|
|
|
|
{
|
|
std::lock_guard<std::mutex> const lock (_mutex);
|
|
uid_after = unsafe_add_model_instance_no_world_upd(std::move(instance));
|
|
}
|
|
|
|
if (from_reloading || uid_after != uid)
|
|
{
|
|
_world->updateTilesModel(&_m2s.at(uid_after), model_update::add);
|
|
}
|
|
|
|
return uid_after;
|
|
}
|
|
std::uint32_t world_model_instances_storage::unsafe_add_model_instance_no_world_upd(ModelInstance instance)
|
|
{
|
|
std::uint32_t uid = instance.uid;
|
|
auto existing_instance = unsafe_get_model_instance(uid);
|
|
|
|
if (existing_instance)
|
|
{
|
|
// instance already loaded
|
|
if (existing_instance.value()->isDuplicateOf(instance))
|
|
{
|
|
_instance_count_per_uid[uid]++;
|
|
return uid;
|
|
}
|
|
}
|
|
else if(!unsafe_uid_is_used(uid))
|
|
{
|
|
/* This causes a crash when undoing while loading a tile, those objects get registered to the action stack
|
|
if (NOGGIT_CUR_ACTION)
|
|
NOGGIT_CUR_ACTION->registerObjectAdded(&instance);
|
|
*/
|
|
_m2s.emplace(uid, instance);
|
|
_instance_count_per_uid[uid] = 1;
|
|
return uid;
|
|
}
|
|
|
|
// the uid is already used for another model/wmo, use a new one
|
|
_uid_duplicates_found = true;
|
|
instance.uid = _world->mapIndex.newGUID();
|
|
|
|
return unsafe_add_model_instance_no_world_upd(std::move(instance));
|
|
}
|
|
|
|
|
|
std::uint32_t world_model_instances_storage::add_wmo_instance(WMOInstance instance, bool from_reloading)
|
|
{
|
|
std::uint32_t uid = instance.uid;
|
|
std::uint32_t uid_after;
|
|
|
|
{
|
|
std::lock_guard<std::mutex> const lock(_mutex);
|
|
uid_after = unsafe_add_wmo_instance_no_world_upd(std::move(instance));
|
|
}
|
|
|
|
if (from_reloading || uid_after != uid)
|
|
{
|
|
_world->updateTilesWMO(&_wmos.at(uid_after), model_update::add);
|
|
}
|
|
|
|
return uid_after;
|
|
}
|
|
std::uint32_t world_model_instances_storage::unsafe_add_wmo_instance_no_world_upd(WMOInstance instance)
|
|
{
|
|
std::uint32_t uid = instance.uid;
|
|
auto existing_instance = unsafe_get_wmo_instance(uid);
|
|
|
|
if (existing_instance)
|
|
{
|
|
// instance already loaded
|
|
if (existing_instance.value()->isDuplicateOf(instance))
|
|
{
|
|
_instance_count_per_uid[uid]++;
|
|
|
|
return uid;
|
|
}
|
|
}
|
|
else if (!unsafe_uid_is_used(uid))
|
|
{
|
|
/*
|
|
if (NOGGIT_CUR_ACTION)
|
|
NOGGIT_CUR_ACTION->registerObjectAdded(&instance);
|
|
*/
|
|
_wmos.emplace(uid, instance);
|
|
_instance_count_per_uid[uid] = 1;
|
|
return uid;
|
|
}
|
|
|
|
// the uid is already used for another model/wmo, use a new one
|
|
_uid_duplicates_found = true;
|
|
instance.uid = _world->mapIndex.newGUID();
|
|
|
|
return unsafe_add_wmo_instance_no_world_upd(std::move(instance));
|
|
}
|
|
|
|
void world_model_instances_storage::delete_instances_from_tile(TileIndex const& tile)
|
|
{
|
|
// std::unique_lock<std::mutex> const lock (_mutex);
|
|
std::vector<selected_object_type> instances_to_remove;
|
|
|
|
for (auto it = _m2s.begin(); it != _m2s.end(); ++it)
|
|
{
|
|
if (TileIndex(it->second.pos) == tile)
|
|
{
|
|
instances_to_remove.push_back(&it->second);
|
|
}
|
|
}
|
|
for (auto it = _wmos.begin(); it != _wmos.end();++it)
|
|
{
|
|
if (TileIndex(it->second.pos) == tile)
|
|
{
|
|
instances_to_remove.push_back(&it->second);
|
|
}
|
|
}
|
|
delete_instances(instances_to_remove);
|
|
}
|
|
|
|
void world_model_instances_storage::delete_instances(std::vector<selected_object_type> const& instances)
|
|
{
|
|
for (auto& obj : instances)
|
|
{
|
|
// should be done in delete_instance
|
|
if (NOGGIT_CUR_ACTION)
|
|
NOGGIT_CUR_ACTION->registerObjectRemoved(obj);
|
|
|
|
if (obj->which() == eMODEL)
|
|
{
|
|
auto instance = static_cast<ModelInstance*>(obj);
|
|
|
|
_world->updateTilesModel(instance, model_update::remove);
|
|
delete_instance(instance->uid);
|
|
}
|
|
else if (obj->which() == eWMO)
|
|
{
|
|
auto instance = static_cast<WMOInstance*>(obj);
|
|
|
|
_world->updateTilesWMO(instance, model_update::remove);
|
|
delete_instance(instance->uid);
|
|
}
|
|
}
|
|
}
|
|
|
|
void world_model_instances_storage::delete_instance(std::uint32_t uid)
|
|
{
|
|
std::unique_lock<std::mutex> const lock (_mutex);
|
|
|
|
if (auto instance = get_instance(uid, false))
|
|
{
|
|
_world->updateTilesEntry(instance.value(), model_update::remove);
|
|
auto obj = std::get<selected_object_type>(instance.value());
|
|
|
|
for (auto& selection_group : _world->_selection_groups)
|
|
{
|
|
if (selection_group.contains_object(obj))
|
|
{
|
|
selection_group.remove_member(obj->uid);
|
|
}
|
|
}
|
|
|
|
if (NOGGIT_CUR_ACTION)
|
|
{
|
|
NOGGIT_CUR_ACTION->registerObjectRemoved(obj);
|
|
}
|
|
}
|
|
|
|
_instance_count_per_uid.erase(uid);
|
|
_m2s.erase(uid);
|
|
_wmos.erase(uid);
|
|
}
|
|
|
|
void world_model_instances_storage::unload_instance_and_remove_from_selection_if_necessary(std::uint32_t uid)
|
|
{
|
|
std::unique_lock<std::mutex> const lock (_mutex);
|
|
|
|
if (!unsafe_uid_is_used(uid))
|
|
{
|
|
LogError << "Trying to unload an instance that wasn't stored" << std::endl;
|
|
return;
|
|
}
|
|
|
|
if (--_instance_count_per_uid.at(uid) == 0)
|
|
{
|
|
_world->remove_from_selection(uid);
|
|
|
|
_instance_count_per_uid.erase(uid);
|
|
_m2s.erase(uid);
|
|
_wmos.erase(uid);
|
|
}
|
|
}
|
|
|
|
void world_model_instances_storage::clear()
|
|
{
|
|
std::unique_lock<std::mutex> const lock (_mutex);
|
|
|
|
_instance_count_per_uid.clear();
|
|
_m2s.clear();
|
|
_wmos.clear();
|
|
}
|
|
|
|
std::optional<ModelInstance*> world_model_instances_storage::get_model_instance(std::uint32_t uid)
|
|
{
|
|
std::unique_lock<std::mutex> const lock (_mutex);
|
|
return unsafe_get_model_instance(uid);
|
|
}
|
|
std::optional<ModelInstance*> world_model_instances_storage::unsafe_get_model_instance(std::uint32_t uid)
|
|
{
|
|
auto it = _m2s.find(uid);
|
|
|
|
if (it != _m2s.end())
|
|
{
|
|
return &it->second;
|
|
}
|
|
else
|
|
{
|
|
return std::nullopt;
|
|
}
|
|
}
|
|
|
|
std::optional<WMOInstance*> world_model_instances_storage::get_wmo_instance(std::uint32_t uid)
|
|
{
|
|
std::unique_lock<std::mutex> const lock (_mutex);
|
|
return unsafe_get_wmo_instance(uid);
|
|
}
|
|
std::optional<WMOInstance*> world_model_instances_storage::unsafe_get_wmo_instance(std::uint32_t uid)
|
|
{
|
|
auto it = _wmos.find(uid);
|
|
|
|
if (it != _wmos.end())
|
|
{
|
|
return &it->second;
|
|
}
|
|
else
|
|
{
|
|
return std::nullopt;
|
|
}
|
|
}
|
|
|
|
std::optional<selection_type> world_model_instances_storage::get_instance(std::uint32_t uid, bool lock)
|
|
{
|
|
if (lock)
|
|
{
|
|
std::unique_lock<std::mutex> const lock(_mutex);
|
|
|
|
auto wmo_it = _wmos.find(uid);
|
|
|
|
if (wmo_it != _wmos.end())
|
|
{
|
|
return selection_type{ &wmo_it->second };
|
|
}
|
|
else
|
|
{
|
|
auto m2_it = _m2s.find(uid);
|
|
|
|
if (m2_it != _m2s.end())
|
|
{
|
|
return selection_type{ &m2_it->second };
|
|
}
|
|
else
|
|
{
|
|
return std::nullopt;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
auto wmo_it = _wmos.find(uid);
|
|
|
|
if (wmo_it != _wmos.end())
|
|
{
|
|
return selection_type{ &wmo_it->second };
|
|
}
|
|
else
|
|
{
|
|
auto m2_it = _m2s.find(uid);
|
|
|
|
if (m2_it != _m2s.end())
|
|
{
|
|
return selection_type{ &m2_it->second };
|
|
}
|
|
else
|
|
{
|
|
return std::nullopt;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool world_model_instances_storage::unsafe_uid_is_used(std::uint32_t uid) const
|
|
{
|
|
return _instance_count_per_uid.find(uid) != _instance_count_per_uid.end();
|
|
}
|
|
|
|
void world_model_instances_storage::clear_duplicates()
|
|
{
|
|
std::unique_lock<std::mutex> const lock (_mutex);
|
|
|
|
int deleted_uids = 0;
|
|
|
|
for (auto lhs(_wmos.begin()); lhs != _wmos.end(); ++lhs)
|
|
{
|
|
for (auto rhs(std::next(lhs)); rhs != _wmos.end();)
|
|
{
|
|
assert(lhs->first != rhs->first);
|
|
|
|
if (lhs->second.isDuplicateOf(rhs->second))
|
|
{
|
|
_world->updateTilesWMO(&rhs->second, model_update::remove);
|
|
|
|
_instance_count_per_uid.erase(rhs->second.uid);
|
|
if (NOGGIT_CUR_ACTION)
|
|
NOGGIT_CUR_ACTION->registerObjectRemoved(&rhs->second);
|
|
rhs = _wmos.erase(rhs);
|
|
deleted_uids++;
|
|
}
|
|
else
|
|
{
|
|
rhs++;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (auto lhs(_m2s.begin()); lhs != _m2s.end(); ++lhs)
|
|
{
|
|
for (auto rhs(std::next(lhs)); rhs != _m2s.end();)
|
|
{
|
|
assert(lhs->first != rhs->first);
|
|
|
|
if (lhs->second.isDuplicateOf(rhs->second))
|
|
{
|
|
_world->updateTilesModel(&rhs->second, model_update::remove);
|
|
|
|
_instance_count_per_uid.erase(rhs->second.uid);
|
|
|
|
if (NOGGIT_CUR_ACTION)
|
|
NOGGIT_CUR_ACTION->registerObjectRemoved(&rhs->second);
|
|
rhs = _m2s.erase(rhs);
|
|
deleted_uids++;
|
|
}
|
|
else
|
|
{
|
|
rhs++;
|
|
}
|
|
}
|
|
}
|
|
|
|
Log << "Deleted " << deleted_uids << " duplicate Model/WMO" << std::endl;
|
|
}
|
|
|
|
void world_model_instances_storage::upload()
|
|
{
|
|
if (_transform_storage_uploaded)
|
|
return;
|
|
|
|
_buffers.upload();
|
|
|
|
gl.genTextures(1, &_m2_instances_transform_buf_tex);
|
|
gl.activeTexture(GL_TEXTURE0);
|
|
gl.bindTexture(GL_TEXTURE_BUFFER, _m2_instances_transform_buf_tex);
|
|
gl.bindBuffer(GL_TEXTURE_BUFFER, _m2_instances_transform_buf);
|
|
gl.bufferData(GL_TEXTURE_BUFFER, _n_allocated_m2_transforms * sizeof(glm::mat4x4), nullptr, GL_DYNAMIC_DRAW);
|
|
gl.texBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, _m2_instances_transform_buf);
|
|
|
|
_transform_storage_uploaded = true;
|
|
}
|
|
|
|
void world_model_instances_storage::unload()
|
|
{
|
|
if (!_transform_storage_uploaded)
|
|
return;
|
|
|
|
gl.deleteTextures(1, &_m2_instances_transform_buf_tex);
|
|
_buffers.unload();
|
|
|
|
_transform_storage_uploaded = false;
|
|
}
|
|
}
|