Undo System: remove accumulate/store modes
[blender.git] / source / blender / editors / physics / particle_edit_undo.c
1 /*
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.
6  *
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.
11  *
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.
15  *
16  * The Original Code is Copyright (C) 2007 by Janne Karhu.
17  * All rights reserved.
18  */
19
20 /** \file blender/editors/physics/particle_edit_undo.c
21  *  \ingroup edphys
22  */
23
24 #include <stdlib.h>
25 #include <math.h>
26 #include <string.h>
27 #include <assert.h>
28
29 #include "MEM_guardedalloc.h"
30
31 #include "DNA_scene_types.h"
32 #include "DNA_meshdata_types.h"
33 #include "DNA_windowmanager_types.h"
34
35 #include "BLI_listbase.h"
36 #include "BLI_utildefines.h"
37
38 #include "BKE_context.h"
39 #include "BKE_particle.h"
40 #include "BKE_pointcache.h"
41 #include "BKE_undo_system.h"
42
43 #include "DEG_depsgraph.h"
44
45 #include "ED_object.h"
46 #include "ED_particle.h"
47 #include "ED_physics.h"
48
49 #include "particle_edit_utildefines.h"
50
51 #include "physics_intern.h"
52
53 /* -------------------------------------------------------------------- */
54 /** \name Undo Conversion
55  * \{ */
56
57 static void undoptcache_from_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
58 {
59         PTCacheEditPoint *point;
60         int i;
61
62         size_t mem_used_prev = MEM_get_memory_in_use();
63
64         undo->totpoint = edit->totpoint;
65
66         if (edit->psys) {
67                 ParticleData *pa;
68
69                 pa = undo->particles = MEM_dupallocN(edit->psys->particles);
70
71                 for (i = 0; i < edit->totpoint; i++, pa++) {
72                         pa->hair = MEM_dupallocN(pa->hair);
73                 }
74
75                 undo->psys_flag = edit->psys->flag;
76         }
77         else {
78                 PTCacheMem *pm;
79
80                 BLI_duplicatelist(&undo->mem_cache, &edit->pid.cache->mem_cache);
81                 pm = undo->mem_cache.first;
82
83                 for (; pm; pm = pm->next) {
84                         for (i = 0; i < BPHYS_TOT_DATA; i++) {
85                                 pm->data[i] = MEM_dupallocN(pm->data[i]);
86                         }
87                 }
88         }
89
90         point = undo->points = MEM_dupallocN(edit->points);
91         undo->totpoint = edit->totpoint;
92
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 */
96         }
97
98         size_t mem_used_curr = MEM_get_memory_in_use();
99
100         undo->undo_size = mem_used_prev < mem_used_curr ? mem_used_curr - mem_used_prev : sizeof(PTCacheUndo);
101 }
102
103 static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
104 {
105         ParticleSystem *psys = edit->psys;
106         ParticleData *pa;
107         HairKey *hkey;
108         POINT_P; KEY_K;
109
110         LOOP_POINTS {
111                 if (psys && psys->particles[p].hair) {
112                         MEM_freeN(psys->particles[p].hair);
113                 }
114
115                 if (point->keys) {
116                         MEM_freeN(point->keys);
117                 }
118         }
119         if (psys && psys->particles) {
120                 MEM_freeN(psys->particles);
121         }
122         if (edit->points) {
123                 MEM_freeN(edit->points);
124         }
125         if (edit->mirror_cache) {
126                 MEM_freeN(edit->mirror_cache);
127                 edit->mirror_cache = NULL;
128         }
129
130         edit->points = MEM_dupallocN(undo->points);
131         edit->totpoint = undo->totpoint;
132
133         LOOP_POINTS {
134                 point->keys = MEM_dupallocN(point->keys);
135         }
136
137         if (psys) {
138                 psys->particles = MEM_dupallocN(undo->particles);
139
140                 psys->totpart = undo->totpoint;
141
142                 LOOP_POINTS {
143                         pa = psys->particles + p;
144                         hkey = pa->hair = MEM_dupallocN(pa->hair);
145
146                         LOOP_KEYS {
147                                 key->co = hkey->co;
148                                 key->time = &hkey->time;
149                                 hkey++;
150                         }
151                 }
152
153                 psys->flag = undo->psys_flag;
154         }
155         else {
156                 PTCacheMem *pm;
157                 int i;
158
159                 BKE_ptcache_free_mem(&edit->pid.cache->mem_cache);
160
161                 BLI_duplicatelist(&edit->pid.cache->mem_cache, &undo->mem_cache);
162
163                 pm = edit->pid.cache->mem_cache.first;
164
165                 for (; pm; pm = pm->next) {
166                         for (i = 0; i < BPHYS_TOT_DATA; i++) {
167                                 pm->data[i] = MEM_dupallocN(pm->data[i]);
168                         }
169                         BKE_ptcache_mem_pointers_init(pm);
170
171                         LOOP_POINTS {
172                                 LOOP_KEYS {
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;
178                                         }
179                                 }
180                                 BKE_ptcache_mem_pointers_incr(pm);
181                         }
182                 }
183         }
184 }
185
186 static void undoptcache_free_data(PTCacheUndo *undo)
187 {
188         PTCacheEditPoint *point;
189         int i;
190
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);
194                 }
195                 if (point->keys) {
196                         MEM_freeN(point->keys);
197                 }
198         }
199         if (undo->points) {
200                 MEM_freeN(undo->points);
201         }
202         if (undo->particles) {
203                 MEM_freeN(undo->particles);
204         }
205         BKE_ptcache_free_mem(&undo->mem_cache);
206 }
207
208 /** \} */
209
210 /* -------------------------------------------------------------------- */
211 /** \name Implements ED Undo System
212  * \{ */
213
214 typedef struct ParticleUndoStep {
215         UndoStep step;
216         UndoRefID_Scene scene_ref;
217         UndoRefID_Object object_ref;
218         PTCacheUndo data;
219 } ParticleUndoStep;
220
221 static bool particle_undosys_poll(struct bContext *C)
222 {
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);
227
228         return (edit != NULL);
229 }
230
231 static bool particle_undosys_step_encode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p)
232 {
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);
239         return true;
240 }
241
242 static void particle_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, int UNUSED(dir))
243 {
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));
247
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);
252         if (edit) {
253                 undoptcache_to_editcache(&us->data, edit);
254                 DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
255         }
256         else {
257                 BLI_assert(0);
258         }
259 }
260
261 static void particle_undosys_step_free(UndoStep *us_p)
262 {
263         ParticleUndoStep *us = (ParticleUndoStep *)us_p;
264         undoptcache_free_data(&us->data);
265 }
266
267 static void particle_undosys_foreach_ID_ref(
268         UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
269 {
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));
273 }
274
275 /* Export for ED_undo_sys. */
276 void ED_particle_undosys_type(UndoType *ut)
277 {
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;
283
284         ut->step_foreach_ID_ref = particle_undosys_foreach_ID_ref;
285
286         ut->use_context = true;
287
288         ut->step_size = sizeof(ParticleUndoStep);
289 }
290
291 /** \} */