Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / physics / particle_edit_undo.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2007 by Janne Karhu.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/physics/particle_edit_undo.c
29  *  \ingroup edphys
30  */
31
32 #include <stdlib.h>
33 #include <math.h>
34 #include <string.h>
35 #include <assert.h>
36
37 #include "MEM_guardedalloc.h"
38
39 #include "DNA_scene_types.h"
40 #include "DNA_meshdata_types.h"
41
42 #include "BLI_listbase.h"
43 #include "BLI_string.h"
44 #include "BLI_utildefines.h"
45
46 #include "BKE_global.h"
47 #include "BKE_particle.h"
48 #include "BKE_pointcache.h"
49
50 #include "DEG_depsgraph.h"
51
52 #include "ED_particle.h"
53
54 #include "particle_edit_utildefines.h"
55
56 #include "physics_intern.h"
57
58
59 static void free_PTCacheUndo(PTCacheUndo *undo)
60 {
61         PTCacheEditPoint *point;
62         int i;
63
64         for (i=0, point=undo->points; i<undo->totpoint; i++, point++) {
65                 if (undo->particles && (undo->particles + i)->hair)
66                         MEM_freeN((undo->particles + i)->hair);
67                 if (point->keys)
68                         MEM_freeN(point->keys);
69         }
70         if (undo->points)
71                 MEM_freeN(undo->points);
72
73         if (undo->particles)
74                 MEM_freeN(undo->particles);
75
76         BKE_ptcache_free_mem(&undo->mem_cache);
77 }
78
79 static void make_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
80 {
81         PTCacheEditPoint *point;
82         int i;
83
84         undo->totpoint= edit->totpoint;
85
86         if (edit->psys) {
87                 ParticleData *pa;
88
89                 pa= undo->particles= MEM_dupallocN(edit->psys->particles);
90
91                 for (i=0; i<edit->totpoint; i++, pa++)
92                         pa->hair= MEM_dupallocN(pa->hair);
93
94                 undo->psys_flag = edit->psys->flag;
95         }
96         else {
97                 PTCacheMem *pm;
98
99                 BLI_duplicatelist(&undo->mem_cache, &edit->pid.cache->mem_cache);
100                 pm = undo->mem_cache.first;
101
102                 for (; pm; pm=pm->next) {
103                         for (i=0; i<BPHYS_TOT_DATA; i++)
104                                 pm->data[i] = MEM_dupallocN(pm->data[i]);
105                 }
106         }
107
108         point= undo->points = MEM_dupallocN(edit->points);
109         undo->totpoint = edit->totpoint;
110
111         for (i=0; i<edit->totpoint; i++, point++) {
112                 point->keys= MEM_dupallocN(point->keys);
113                 /* no need to update edit key->co & key->time pointers here */
114         }
115 }
116
117 static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
118 {
119         ParticleSystem *psys = edit->psys;
120         ParticleData *pa;
121         HairKey *hkey;
122         POINT_P; KEY_K;
123
124         LOOP_POINTS {
125                 if (psys && psys->particles[p].hair)
126                         MEM_freeN(psys->particles[p].hair);
127
128                 if (point->keys)
129                         MEM_freeN(point->keys);
130         }
131         if (psys && psys->particles)
132                 MEM_freeN(psys->particles);
133         if (edit->points)
134                 MEM_freeN(edit->points);
135         if (edit->mirror_cache) {
136                 MEM_freeN(edit->mirror_cache);
137                 edit->mirror_cache= NULL;
138         }
139
140         edit->points= MEM_dupallocN(undo->points);
141         edit->totpoint = undo->totpoint;
142
143         LOOP_POINTS {
144                 point->keys= MEM_dupallocN(point->keys);
145         }
146
147         if (psys) {
148                 psys->particles= MEM_dupallocN(undo->particles);
149
150                 psys->totpart= undo->totpoint;
151
152                 LOOP_POINTS {
153                         pa = psys->particles + p;
154                         hkey= pa->hair = MEM_dupallocN(pa->hair);
155
156                         LOOP_KEYS {
157                                 key->co= hkey->co;
158                                 key->time= &hkey->time;
159                                 hkey++;
160                         }
161                 }
162
163                 psys->flag = undo->psys_flag;
164         }
165         else {
166                 PTCacheMem *pm;
167                 int i;
168
169                 BKE_ptcache_free_mem(&edit->pid.cache->mem_cache);
170
171                 BLI_duplicatelist(&edit->pid.cache->mem_cache, &undo->mem_cache);
172
173                 pm = edit->pid.cache->mem_cache.first;
174
175                 for (; pm; pm=pm->next) {
176                         for (i=0; i<BPHYS_TOT_DATA; i++)
177                                 pm->data[i] = MEM_dupallocN(pm->data[i]);
178
179                         BKE_ptcache_mem_pointers_init(pm);
180
181                         LOOP_POINTS {
182                                 LOOP_KEYS {
183                                         if ((int)key->ftime == (int)pm->frame) {
184                                                 key->co = pm->cur[BPHYS_DATA_LOCATION];
185                                                 key->vel = pm->cur[BPHYS_DATA_VELOCITY];
186                                                 key->rot = pm->cur[BPHYS_DATA_ROTATION];
187                                                 key->time = &key->ftime;
188                                         }
189                                 }
190                                 BKE_ptcache_mem_pointers_incr(pm);
191                         }
192                 }
193         }
194 }
195
196 void PE_undo_push(Scene *scene, ViewLayer *view_layer, const char *str)
197 {
198         PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
199         PTCacheUndo *undo;
200         int nr;
201
202         if (!edit) return;
203
204         /* remove all undos after (also when curundo==NULL) */
205         while (edit->undo.last != edit->curundo) {
206                 undo= edit->undo.last;
207                 BLI_remlink(&edit->undo, undo);
208                 free_PTCacheUndo(undo);
209                 MEM_freeN(undo);
210         }
211
212         /* make new */
213         edit->curundo= undo= MEM_callocN(sizeof(PTCacheUndo), "particle undo file");
214         BLI_strncpy(undo->name, str, sizeof(undo->name));
215         BLI_addtail(&edit->undo, undo);
216
217         /* and limit amount to the maximum */
218         nr= 0;
219         undo= edit->undo.last;
220         while (undo) {
221                 nr++;
222                 if (nr==U.undosteps) break;
223                 undo= undo->prev;
224         }
225         if (undo) {
226                 while (edit->undo.first != undo) {
227                         PTCacheUndo *first= edit->undo.first;
228                         BLI_remlink(&edit->undo, first);
229                         free_PTCacheUndo(first);
230                         MEM_freeN(first);
231                 }
232         }
233
234         /* copy  */
235         make_PTCacheUndo(edit, edit->curundo);
236 }
237
238 void PE_undo_step(Scene *scene, ViewLayer *view_layer, int step)
239 {
240         PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
241
242         if (!edit) return;
243
244         if (step==0) {
245                 get_PTCacheUndo(edit, edit->curundo);
246         }
247         else if (step==1) {
248
249                 if (edit->curundo==NULL || edit->curundo->prev==NULL) {
250                         /* pass */
251                 }
252                 else {
253                         if (G.debug & G_DEBUG) printf("undo %s\n", edit->curundo->name);
254                         edit->curundo= edit->curundo->prev;
255                         get_PTCacheUndo(edit, edit->curundo);
256                 }
257         }
258         else {
259                 /* curundo has to remain current situation! */
260
261                 if (edit->curundo==NULL || edit->curundo->next==NULL) {
262                         /* pass */
263                 }
264                 else {
265                         get_PTCacheUndo(edit, edit->curundo->next);
266                         edit->curundo= edit->curundo->next;
267                         if (G.debug & G_DEBUG) printf("redo %s\n", edit->curundo->name);
268                 }
269         }
270
271         DEG_id_tag_update(&OBACT(view_layer)->id, OB_RECALC_DATA);
272 }
273
274 bool PE_undo_is_valid(Scene *scene, ViewLayer *view_layer)
275 {
276         PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
277
278         if (edit) {
279                 return (edit->undo.last != edit->undo.first);
280         }
281         return 0;
282 }
283
284 void PTCacheUndo_clear(PTCacheEdit *edit)
285 {
286         PTCacheUndo *undo;
287
288         if (edit==NULL) return;
289
290         undo= edit->undo.first;
291         while (undo) {
292                 free_PTCacheUndo(undo);
293                 undo= undo->next;
294         }
295         BLI_freelistN(&edit->undo);
296         edit->curundo= NULL;
297 }
298
299 void PE_undo(Scene *scene, ViewLayer *view_layer)
300 {
301         PE_undo_step(scene, view_layer, 1);
302 }
303
304 void PE_redo(Scene *scene, ViewLayer *view_layer)
305 {
306         PE_undo_step(scene, view_layer, -1);
307 }
308
309 void PE_undo_number(Scene *scene, ViewLayer *view_layer, int nr)
310 {
311         PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
312         PTCacheUndo *undo;
313         int a=0;
314
315         for (undo= edit->undo.first; undo; undo= undo->next, a++) {
316                 if (a==nr) break;
317         }
318         edit->curundo= undo;
319         PE_undo_step(scene, view_layer, 0);
320 }
321
322
323 /* get name of undo item, return null if no item with this index */
324 /* if active pointer, set it to 1 if true */
325 const char *PE_undo_get_name(Scene *scene, ViewLayer *view_layer, int nr, bool *r_active)
326 {
327         PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
328         PTCacheUndo *undo;
329
330         if (r_active) *r_active = false;
331
332         if (edit) {
333                 undo= BLI_findlink(&edit->undo, nr);
334                 if (undo) {
335                         if (r_active && (undo == edit->curundo)) {
336                                 *r_active = true;
337                         }
338                         return undo->name;
339                 }
340         }
341         return NULL;
342 }