Files
test2/source/blender/editors/physics/particle_edit_undo.cc
Brecht Van Lommel 8d8e61fefd Logging: Change various categories and log levels
* Remove bke, ed and wm prefixes
* Add prefixes like: geom, object, blend, lib.
* Shorten some category names
* A few log level changes to improve --log-level info output

Pull Request: https://projects.blender.org/blender/blender/pulls/140244
2025-07-09 20:59:26 +02:00

304 lines
8.3 KiB
C++

/* SPDX-FileCopyrightText: 2007 by Janne Karhu. All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edphys
*/
#include <cstdlib>
#include <cstring>
#include "MEM_guardedalloc.h"
#include "CLG_log.h"
#include "DNA_scene_types.h"
#include "DNA_windowmanager_types.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BKE_context.hh"
#include "BKE_layer.hh"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_undo_system.hh"
#include "DEG_depsgraph.hh"
#include "ED_object.hh"
#include "ED_particle.hh"
#include "ED_physics.hh"
#include "ED_undo.hh"
#include "particle_edit_utildefines.h"
/** Only needed this locally. */
static CLG_LogRef LOG = {"undo.particle"};
/* -------------------------------------------------------------------- */
/** \name Undo Conversion
* \{ */
static void undoptcache_from_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
{
PTCacheEditPoint *point;
size_t mem_used_prev = MEM_get_memory_in_use();
undo->totpoint = edit->totpoint;
if (edit->psys) {
ParticleData *pa;
pa = undo->particles = static_cast<ParticleData *>(MEM_dupallocN(edit->psys->particles));
for (int i = 0; i < edit->totpoint; i++, pa++) {
pa->hair = static_cast<HairKey *>(MEM_dupallocN(pa->hair));
}
undo->psys_flag = edit->psys->flag;
}
else {
PTCacheMem *pm;
BLI_duplicatelist(&undo->mem_cache, &edit->pid.cache->mem_cache);
pm = static_cast<PTCacheMem *>(undo->mem_cache.first);
for (; pm; pm = pm->next) {
for (int i = 0; i < BPHYS_TOT_DATA; i++) {
pm->data[i] = MEM_dupallocN(pm->data[i]);
}
}
}
point = undo->points = static_cast<PTCacheEditPoint *>(MEM_dupallocN(edit->points));
undo->totpoint = edit->totpoint;
for (int i = 0; i < edit->totpoint; i++, point++) {
point->keys = static_cast<PTCacheEditKey *>(MEM_dupallocN(point->keys));
/* no need to update edit key->co & key->time pointers here */
}
size_t mem_used_curr = MEM_get_memory_in_use();
undo->undo_size = mem_used_prev < mem_used_curr ? mem_used_curr - mem_used_prev :
sizeof(PTCacheUndo);
}
static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
{
ParticleSystem *psys = edit->psys;
ParticleData *pa;
HairKey *hkey;
POINT_P;
KEY_K;
LOOP_POINTS {
if (psys && psys->particles[p].hair) {
MEM_freeN(psys->particles[p].hair);
}
if (point->keys) {
MEM_freeN(point->keys);
}
}
if (psys && psys->particles) {
MEM_freeN(psys->particles);
}
if (edit->points) {
MEM_freeN(edit->points);
}
MEM_SAFE_FREE(edit->mirror_cache);
edit->points = static_cast<PTCacheEditPoint *>(MEM_dupallocN(undo->points));
edit->totpoint = undo->totpoint;
LOOP_POINTS {
point->keys = static_cast<PTCacheEditKey *>(MEM_dupallocN(point->keys));
}
if (psys) {
psys->particles = static_cast<ParticleData *>(MEM_dupallocN(undo->particles));
psys->totpart = undo->totpoint;
LOOP_POINTS {
pa = psys->particles + p;
hkey = pa->hair = static_cast<HairKey *>(MEM_dupallocN(pa->hair));
LOOP_KEYS {
key->co = hkey->co;
key->time = &hkey->time;
hkey++;
}
}
psys->flag = undo->psys_flag;
}
else {
PTCacheMem *pm;
int i;
BKE_ptcache_free_mem(&edit->pid.cache->mem_cache);
BLI_duplicatelist(&edit->pid.cache->mem_cache, &undo->mem_cache);
pm = static_cast<PTCacheMem *>(edit->pid.cache->mem_cache.first);
for (; pm; pm = pm->next) {
for (i = 0; i < BPHYS_TOT_DATA; i++) {
pm->data[i] = MEM_dupallocN(pm->data[i]);
}
void *cur[BPHYS_TOT_DATA];
BKE_ptcache_mem_pointers_init(pm, cur);
LOOP_POINTS {
LOOP_KEYS {
if (int(key->ftime) == int(pm->frame)) {
key->co = static_cast<float *>(cur[BPHYS_DATA_LOCATION]);
key->vel = static_cast<float *>(cur[BPHYS_DATA_VELOCITY]);
key->rot = static_cast<float *>(cur[BPHYS_DATA_ROTATION]);
key->time = &key->ftime;
}
}
BKE_ptcache_mem_pointers_incr(cur);
}
}
}
}
static void undoptcache_free_data(PTCacheUndo *undo)
{
PTCacheEditPoint *point;
int i;
for (i = 0, point = undo->points; i < undo->totpoint; i++, point++) {
if (undo->particles && (undo->particles + i)->hair) {
MEM_freeN((undo->particles + i)->hair);
}
if (point->keys) {
MEM_freeN(point->keys);
}
}
if (undo->points) {
MEM_freeN(undo->points);
}
if (undo->particles) {
MEM_freeN(undo->particles);
}
BKE_ptcache_free_mem(&undo->mem_cache);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Implements ED Undo System
* \{ */
struct ParticleUndoStep {
UndoStep step;
/** See #ED_undo_object_editmode_validate_scene_from_windows code comment for details. */
UndoRefID_Scene scene_ref;
UndoRefID_Object object_ref;
PTCacheUndo data;
};
static bool particle_undosys_poll(bContext *C)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
BKE_view_layer_synced_ensure(scene, view_layer);
Object *ob = BKE_view_layer_active_object_get(view_layer);
PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
return (edit != nullptr);
}
static bool particle_undosys_step_encode(bContext *C, Main * /*bmain*/, UndoStep *us_p)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
ParticleUndoStep *us = (ParticleUndoStep *)us_p;
ViewLayer *view_layer = CTX_data_view_layer(C);
us->scene_ref.ptr = CTX_data_scene(C);
BKE_view_layer_synced_ensure(us->scene_ref.ptr, view_layer);
us->object_ref.ptr = BKE_view_layer_active_object_get(view_layer);
PTCacheEdit *edit = PE_get_current(depsgraph, us->scene_ref.ptr, us->object_ref.ptr);
undoptcache_from_editcache(&us->data, edit);
return true;
}
static void particle_undosys_step_decode(
bContext *C, Main * /*bmain*/, UndoStep *us_p, const eUndoStepDir /*dir*/, bool /*is_final*/)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
ParticleUndoStep *us = (ParticleUndoStep *)us_p;
Scene *scene = us->scene_ref.ptr;
ViewLayer *view_layer = CTX_data_view_layer(C);
/* Only to correct the `view_layer` which might not match the scene
* (in the case of undoing with multiple windows). */
ED_undo_object_editmode_validate_scene_from_windows(
CTX_wm_manager(C), us->scene_ref.ptr, &scene, &view_layer);
Object *ob = us->object_ref.ptr;
ED_object_particle_edit_mode_enter_ex(depsgraph, scene, ob);
PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
/* While this shouldn't happen, entering particle edit-mode uses a more complex
* setup compared to most other modes which we can't ensure succeeds. */
if (UNLIKELY(edit == nullptr)) {
BLI_assert(0);
return;
}
undoptcache_to_editcache(&us->data, edit);
ParticleEditSettings *pset = &scene->toolsettings->particle;
if ((pset->flag & PE_DRAW_PART) != 0) {
psys_free_path_cache(nullptr, edit);
BKE_particle_batch_cache_dirty_tag(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
}
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
ED_undo_object_set_active_or_warn(scene, view_layer, ob, us_p->name, &LOG);
/* Check after setting active (unless undoing into another scene). */
BLI_assert(particle_undosys_poll(C) || (scene != CTX_data_scene(C)));
}
static void particle_undosys_step_free(UndoStep *us_p)
{
ParticleUndoStep *us = (ParticleUndoStep *)us_p;
undoptcache_free_data(&us->data);
}
static void particle_undosys_foreach_ID_ref(UndoStep *us_p,
UndoTypeForEachIDRefFn foreach_ID_ref_fn,
void *user_data)
{
ParticleUndoStep *us = (ParticleUndoStep *)us_p;
foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->scene_ref));
foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->object_ref));
}
void ED_particle_undosys_type(UndoType *ut)
{
ut->name = "Edit Particle";
ut->poll = particle_undosys_poll;
ut->step_encode = particle_undosys_step_encode;
ut->step_decode = particle_undosys_step_decode;
ut->step_free = particle_undosys_step_free;
ut->step_foreach_ID_ref = particle_undosys_foreach_ID_ref;
ut->flags = UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE;
ut->step_size = sizeof(ParticleUndoStep);
}
/** \} */