2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * The Original Code is Copyright (C) 2007 by Janne Karhu.
17 * All rights reserved.
20 /** \file blender/editors/physics/particle_edit_undo.c
29 #include "MEM_guardedalloc.h"
31 #include "DNA_scene_types.h"
32 #include "DNA_meshdata_types.h"
33 #include "DNA_windowmanager_types.h"
35 #include "BLI_listbase.h"
36 #include "BLI_utildefines.h"
38 #include "BKE_context.h"
39 #include "BKE_particle.h"
40 #include "BKE_pointcache.h"
41 #include "BKE_undo_system.h"
43 #include "DEG_depsgraph.h"
45 #include "ED_object.h"
46 #include "ED_particle.h"
47 #include "ED_physics.h"
49 #include "particle_edit_utildefines.h"
51 #include "physics_intern.h"
53 /* -------------------------------------------------------------------- */
54 /** \name Undo Conversion
57 static void undoptcache_from_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
59 PTCacheEditPoint *point;
62 size_t mem_used_prev = MEM_get_memory_in_use();
64 undo->totpoint = edit->totpoint;
69 pa = undo->particles = MEM_dupallocN(edit->psys->particles);
71 for (i = 0; i < edit->totpoint; i++, pa++) {
72 pa->hair = MEM_dupallocN(pa->hair);
75 undo->psys_flag = edit->psys->flag;
80 BLI_duplicatelist(&undo->mem_cache, &edit->pid.cache->mem_cache);
81 pm = undo->mem_cache.first;
83 for (; pm; pm = pm->next) {
84 for (i = 0; i < BPHYS_TOT_DATA; i++) {
85 pm->data[i] = MEM_dupallocN(pm->data[i]);
90 point = undo->points = MEM_dupallocN(edit->points);
91 undo->totpoint = edit->totpoint;
93 for (i = 0; i < edit->totpoint; i++, point++) {
94 point->keys = MEM_dupallocN(point->keys);
95 /* no need to update edit key->co & key->time pointers here */
98 size_t mem_used_curr = MEM_get_memory_in_use();
100 undo->undo_size = mem_used_prev < mem_used_curr ? mem_used_curr - mem_used_prev : sizeof(PTCacheUndo);
103 static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
105 ParticleSystem *psys = edit->psys;
111 if (psys && psys->particles[p].hair) {
112 MEM_freeN(psys->particles[p].hair);
116 MEM_freeN(point->keys);
119 if (psys && psys->particles) {
120 MEM_freeN(psys->particles);
123 MEM_freeN(edit->points);
125 if (edit->mirror_cache) {
126 MEM_freeN(edit->mirror_cache);
127 edit->mirror_cache = NULL;
130 edit->points = MEM_dupallocN(undo->points);
131 edit->totpoint = undo->totpoint;
134 point->keys = MEM_dupallocN(point->keys);
138 psys->particles = MEM_dupallocN(undo->particles);
140 psys->totpart = undo->totpoint;
143 pa = psys->particles + p;
144 hkey = pa->hair = MEM_dupallocN(pa->hair);
148 key->time = &hkey->time;
153 psys->flag = undo->psys_flag;
159 BKE_ptcache_free_mem(&edit->pid.cache->mem_cache);
161 BLI_duplicatelist(&edit->pid.cache->mem_cache, &undo->mem_cache);
163 pm = edit->pid.cache->mem_cache.first;
165 for (; pm; pm = pm->next) {
166 for (i = 0; i < BPHYS_TOT_DATA; i++) {
167 pm->data[i] = MEM_dupallocN(pm->data[i]);
169 BKE_ptcache_mem_pointers_init(pm);
173 if ((int)key->ftime == (int)pm->frame) {
174 key->co = pm->cur[BPHYS_DATA_LOCATION];
175 key->vel = pm->cur[BPHYS_DATA_VELOCITY];
176 key->rot = pm->cur[BPHYS_DATA_ROTATION];
177 key->time = &key->ftime;
180 BKE_ptcache_mem_pointers_incr(pm);
186 static void undoptcache_free_data(PTCacheUndo *undo)
188 PTCacheEditPoint *point;
191 for (i = 0, point = undo->points; i < undo->totpoint; i++, point++) {
192 if (undo->particles && (undo->particles + i)->hair) {
193 MEM_freeN((undo->particles + i)->hair);
196 MEM_freeN(point->keys);
200 MEM_freeN(undo->points);
202 if (undo->particles) {
203 MEM_freeN(undo->particles);
205 BKE_ptcache_free_mem(&undo->mem_cache);
210 /* -------------------------------------------------------------------- */
211 /** \name Implements ED Undo System
214 typedef struct ParticleUndoStep {
216 UndoRefID_Scene scene_ref;
217 UndoRefID_Object object_ref;
221 static bool particle_undosys_poll(struct bContext *C)
223 Scene *scene = CTX_data_scene(C);
224 ViewLayer *view_layer = CTX_data_view_layer(C);
225 Object *ob = OBACT(view_layer);
226 PTCacheEdit *edit = PE_get_current(scene, ob);
228 return (edit != NULL);
231 static bool particle_undosys_step_encode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p)
233 ParticleUndoStep *us = (ParticleUndoStep *)us_p;
234 ViewLayer *view_layer = CTX_data_view_layer(C);
235 us->scene_ref.ptr = CTX_data_scene(C);
236 us->object_ref.ptr = OBACT(view_layer);
237 PTCacheEdit *edit = PE_get_current(us->scene_ref.ptr, us->object_ref.ptr);
238 undoptcache_from_editcache(&us->data, edit);
242 static void particle_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, int UNUSED(dir))
244 /* TODO(campbell): undo_system: use low-level API to set mode. */
245 ED_object_mode_set(C, OB_MODE_PARTICLE_EDIT);
246 BLI_assert(particle_undosys_poll(C));
248 ParticleUndoStep *us = (ParticleUndoStep *)us_p;
249 Scene *scene = us->scene_ref.ptr;
250 Object *ob = us->object_ref.ptr;
251 PTCacheEdit *edit = PE_get_current(scene, ob);
253 undoptcache_to_editcache(&us->data, edit);
254 DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
261 static void particle_undosys_step_free(UndoStep *us_p)
263 ParticleUndoStep *us = (ParticleUndoStep *)us_p;
264 undoptcache_free_data(&us->data);
267 static void particle_undosys_foreach_ID_ref(
268 UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
270 ParticleUndoStep *us = (ParticleUndoStep *)us_p;
271 foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->scene_ref));
272 foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->object_ref));
275 /* Export for ED_undo_sys. */
276 void ED_particle_undosys_type(UndoType *ut)
278 ut->name = "Edit Particle";
279 ut->poll = particle_undosys_poll;
280 ut->step_encode = particle_undosys_step_encode;
281 ut->step_decode = particle_undosys_step_decode;
282 ut->step_free = particle_undosys_step_free;
284 ut->step_foreach_ID_ref = particle_undosys_foreach_ID_ref;
286 ut->use_context = true;
288 ut->step_size = sizeof(ParticleUndoStep);