diff options
Diffstat (limited to 'source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc')
-rw-r--r-- | source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc new file mode 100644 index 00000000000..a6a042f3e7b --- /dev/null +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc @@ -0,0 +1,182 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2019 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup depsgraph + */ + +#include "intern/eval/deg_eval_runtime_backup_object.h" + +#include <cstring> + +#include "DNA_mesh_types.h" + +#include "BLI_listbase.h" + +#include "BKE_action.h" +#include "BKE_object.h" + +namespace DEG { + +ObjectRuntimeBackup::ObjectRuntimeBackup(const Depsgraph * /*depsgraph*/) + : base_flag(0), base_local_view_bits(0) +{ + /* TODO(sergey): Use something like BKE_object_runtime_reset(). */ + memset(&runtime, 0, sizeof(runtime)); +} + +void ObjectRuntimeBackup::init_from_object(Object *object) +{ + /* Store evaluated mesh and curve_cache, and make sure we don't free it. */ + Mesh *mesh_eval = object->runtime.mesh_eval; + runtime = object->runtime; + BKE_object_runtime_reset(object); + /* Keep bbox (for now at least). */ + object->runtime.bb = runtime.bb; + /* Object update will override actual object->data to an evaluated version. + * Need to make sure we don't have data set to evaluated one before free + * anything. */ + if (mesh_eval != NULL && object->data == mesh_eval) { + object->data = runtime.mesh_orig; + } + /* Make a backup of base flags. */ + base_flag = object->base_flag; + base_local_view_bits = object->base_local_view_bits; + /* Backup tuntime data of all modifiers. */ + backup_modifier_runtime_data(object); + /* Backup runtime data of all pose channels. */ + backup_pose_channel_runtime_data(object); +} + +inline ModifierDataBackupID create_modifier_data_id(const ModifierData *modifier_data) +{ + return ModifierDataBackupID(modifier_data->orig_modifier_data, + static_cast<ModifierType>(modifier_data->type)); +} + +void ObjectRuntimeBackup::backup_modifier_runtime_data(Object *object) +{ + LISTBASE_FOREACH (ModifierData *, modifier_data, &object->modifiers) { + if (modifier_data->runtime == NULL) { + continue; + } + BLI_assert(modifier_data->orig_modifier_data != NULL); + ModifierDataBackupID modifier_data_id = create_modifier_data_id(modifier_data); + modifier_runtime_data.insert(make_pair(modifier_data_id, modifier_data->runtime)); + modifier_data->runtime = NULL; + } +} + +void ObjectRuntimeBackup::backup_pose_channel_runtime_data(Object *object) +{ + if (object->pose != NULL) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + /* This is NULL in Edit mode. */ + if (pchan->orig_pchan != NULL) { + pose_channel_runtime_data[pchan->orig_pchan] = pchan->runtime; + BKE_pose_channel_runtime_reset(&pchan->runtime); + } + } + } +} + +void ObjectRuntimeBackup::restore_to_object(Object *object) +{ + Mesh *mesh_orig = object->runtime.mesh_orig; + BoundBox *bb = object->runtime.bb; + object->runtime = runtime; + object->runtime.mesh_orig = mesh_orig; + object->runtime.bb = bb; + if (object->type == OB_MESH && object->runtime.mesh_eval != NULL) { + if (object->id.recalc & ID_RECALC_GEOMETRY) { + /* If geometry is tagged for update it means, that part of + * evaluated mesh are not valid anymore. In this case we can not + * have any "persistent" pointers to point to an invalid data. + * + * We restore object's data datablock to an original copy of + * that datablock. */ + object->data = mesh_orig; + + /* After that, immediately free the invalidated caches. */ + BKE_object_free_derived_caches(object); + } + else { + Mesh *mesh_eval = object->runtime.mesh_eval; + /* Do same thing as object update: override actual object data + * pointer with evaluated datablock. */ + object->data = mesh_eval; + /* Evaluated mesh simply copied edit_mesh pointer from + * original mesh during update, need to make sure no dead + * pointers are left behind. */ + mesh_eval->edit_mesh = mesh_orig->edit_mesh; + } + } + object->base_flag = base_flag; + object->base_local_view_bits = base_local_view_bits; + /* Restore modifier's runtime data. + * NOTE: Data of unused modifiers will be freed there. */ + restore_modifier_runtime_data(object); + restore_pose_channel_runtime_data(object); +} + +void ObjectRuntimeBackup::restore_modifier_runtime_data(Object *object) +{ + LISTBASE_FOREACH (ModifierData *, modifier_data, &object->modifiers) { + BLI_assert(modifier_data->orig_modifier_data != NULL); + ModifierDataBackupID modifier_data_id = create_modifier_data_id(modifier_data); + ModifierRuntimeDataBackup::iterator runtime_data_iterator = modifier_runtime_data.find( + modifier_data_id); + if (runtime_data_iterator != modifier_runtime_data.end()) { + modifier_data->runtime = runtime_data_iterator->second; + runtime_data_iterator->second = NULL; + } + } + for (ModifierRuntimeDataBackup::value_type value : modifier_runtime_data) { + const ModifierDataBackupID modifier_data_id = value.first; + void *runtime = value.second; + if (value.second == NULL) { + continue; + } + const ModifierTypeInfo *modifier_type_info = modifierType_getInfo(modifier_data_id.type); + BLI_assert(modifier_type_info != NULL); + modifier_type_info->freeRuntimeData(runtime); + } +} + +void ObjectRuntimeBackup::restore_pose_channel_runtime_data(Object *object) +{ + if (object->pose != NULL) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + /* This is NULL in Edit mode. */ + if (pchan->orig_pchan != NULL) { + PoseChannelRuntimeDataBackup::iterator runtime_data_iterator = + pose_channel_runtime_data.find(pchan->orig_pchan); + if (runtime_data_iterator != pose_channel_runtime_data.end()) { + pchan->runtime = runtime_data_iterator->second; + pose_channel_runtime_data.erase(runtime_data_iterator); + } + } + } + } + for (PoseChannelRuntimeDataBackup::value_type &value : pose_channel_runtime_data) { + BKE_pose_channel_runtime_free(&value.second); + } +} + +} // namespace DEG |