UI: preset popover buttons in panel headers.
[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 #include "DNA_windowmanager_types.h"
42
43 #include "BLI_listbase.h"
44 #include "BLI_string.h"
45 #include "BLI_utildefines.h"
46
47 #include "BKE_particle.h"
48 #include "BKE_pointcache.h"
49 #include "BKE_context.h"
50 #include "BKE_undo_system.h"
51
52 #include "DEG_depsgraph.h"
53
54 #include "ED_object.h"
55 #include "ED_particle.h"
56 #include "ED_physics.h"
57
58 #include "particle_edit_utildefines.h"
59
60 #include "physics_intern.h"
61
62 /* -------------------------------------------------------------------- */
63 /** \name Undo Conversion
64  * \{ */
65
66 static void undoptcache_from_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
67 {
68         PTCacheEditPoint *point;
69         int i;
70
71         size_t mem_used_prev = MEM_get_memory_in_use();
72
73         undo->totpoint= edit->totpoint;
74
75         if (edit->psys) {
76                 ParticleData *pa;
77
78                 pa= undo->particles= MEM_dupallocN(edit->psys->particles);
79
80                 for (i=0; i<edit->totpoint; i++, pa++) {
81                         pa->hair= MEM_dupallocN(pa->hair);
82                 }
83
84                 undo->psys_flag = edit->psys->flag;
85         }
86         else {
87                 PTCacheMem *pm;
88
89                 BLI_duplicatelist(&undo->mem_cache, &edit->pid.cache->mem_cache);
90                 pm = undo->mem_cache.first;
91
92                 for (; pm; pm=pm->next) {
93                         for (i=0; i<BPHYS_TOT_DATA; i++) {
94                                 pm->data[i] = MEM_dupallocN(pm->data[i]);
95                         }
96                 }
97         }
98
99         point= undo->points = MEM_dupallocN(edit->points);
100         undo->totpoint = edit->totpoint;
101
102         for (i=0; i<edit->totpoint; i++, point++) {
103                 point->keys= MEM_dupallocN(point->keys);
104                 /* no need to update edit key->co & key->time pointers here */
105         }
106
107         size_t mem_used_curr = MEM_get_memory_in_use();
108
109         undo->undo_size = mem_used_prev < mem_used_curr ? mem_used_curr - mem_used_prev : sizeof(PTCacheUndo);
110 }
111
112 static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
113 {
114         ParticleSystem *psys = edit->psys;
115         ParticleData *pa;
116         HairKey *hkey;
117         POINT_P; KEY_K;
118
119         LOOP_POINTS {
120                 if (psys && psys->particles[p].hair) {
121                         MEM_freeN(psys->particles[p].hair);
122                 }
123
124                 if (point->keys) {
125                         MEM_freeN(point->keys);
126                 }
127         }
128         if (psys && psys->particles) {
129                 MEM_freeN(psys->particles);
130         }
131         if (edit->points) {
132                 MEM_freeN(edit->points);
133         }
134         if (edit->mirror_cache) {
135                 MEM_freeN(edit->mirror_cache);
136                 edit->mirror_cache= NULL;
137         }
138
139         edit->points= MEM_dupallocN(undo->points);
140         edit->totpoint = undo->totpoint;
141
142         LOOP_POINTS {
143                 point->keys= MEM_dupallocN(point->keys);
144         }
145
146         if (psys) {
147                 psys->particles= MEM_dupallocN(undo->particles);
148
149                 psys->totpart= undo->totpoint;
150
151                 LOOP_POINTS {
152                         pa = psys->particles + p;
153                         hkey= pa->hair = MEM_dupallocN(pa->hair);
154
155                         LOOP_KEYS {
156                                 key->co= hkey->co;
157                                 key->time= &hkey->time;
158                                 hkey++;
159                         }
160                 }
161
162                 psys->flag = undo->psys_flag;
163         }
164         else {
165                 PTCacheMem *pm;
166                 int i;
167
168                 BKE_ptcache_free_mem(&edit->pid.cache->mem_cache);
169
170                 BLI_duplicatelist(&edit->pid.cache->mem_cache, &undo->mem_cache);
171
172                 pm = edit->pid.cache->mem_cache.first;
173
174                 for (; pm; pm=pm->next) {
175                         for (i = 0; i < BPHYS_TOT_DATA; i++) {
176                                 pm->data[i] = MEM_dupallocN(pm->data[i]);
177                         }
178                         BKE_ptcache_mem_pointers_init(pm);
179
180                         LOOP_POINTS {
181                                 LOOP_KEYS {
182                                         if ((int)key->ftime == (int)pm->frame) {
183                                                 key->co = pm->cur[BPHYS_DATA_LOCATION];
184                                                 key->vel = pm->cur[BPHYS_DATA_VELOCITY];
185                                                 key->rot = pm->cur[BPHYS_DATA_ROTATION];
186                                                 key->time = &key->ftime;
187                                         }
188                                 }
189                                 BKE_ptcache_mem_pointers_incr(pm);
190                         }
191                 }
192         }
193 }
194
195 static void undoptcache_free_data(PTCacheUndo *undo)
196 {
197         PTCacheEditPoint *point;
198         int i;
199
200         for (i = 0, point=undo->points; i < undo->totpoint; i++, point++) {
201                 if (undo->particles && (undo->particles + i)->hair) {
202                         MEM_freeN((undo->particles + i)->hair);
203                 }
204                 if (point->keys) {
205                         MEM_freeN(point->keys);
206                 }
207         }
208         if (undo->points) {
209                 MEM_freeN(undo->points);
210         }
211         if (undo->particles) {
212                 MEM_freeN(undo->particles);
213         }
214         BKE_ptcache_free_mem(&undo->mem_cache);
215 }
216
217 /** \} */
218
219 /* -------------------------------------------------------------------- */
220 /** \name Implements ED Undo System
221  * \{ */
222
223 typedef struct ParticleUndoStep {
224         UndoStep step;
225         UndoRefID_Scene scene_ref;
226         UndoRefID_Object object_ref;
227         PTCacheUndo data;
228 } ParticleUndoStep;
229
230 static bool particle_undosys_poll(struct bContext *C)
231 {
232         Scene *scene = CTX_data_scene(C);
233         ViewLayer *view_layer = CTX_data_view_layer(C);
234         Object *ob = OBACT(view_layer);
235         PTCacheEdit *edit = PE_get_current(scene, ob);
236
237         return (edit != NULL);
238 }
239
240 static bool particle_undosys_step_encode(struct bContext *C, UndoStep *us_p)
241 {
242         ParticleUndoStep *us = (ParticleUndoStep *)us_p;
243         ViewLayer *view_layer = CTX_data_view_layer(C);
244         us->scene_ref.ptr = CTX_data_scene(C);
245         us->object_ref.ptr = OBACT(view_layer);
246         PTCacheEdit *edit = PE_get_current(us->scene_ref.ptr, us->object_ref.ptr);
247         undoptcache_from_editcache(&us->data, edit);
248         return true;
249 }
250
251 static void particle_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
252 {
253         /* TODO(campbell): undo_system: use low-level API to set mode. */
254         ED_object_mode_set(C, OB_MODE_PARTICLE_EDIT);
255         BLI_assert(particle_undosys_poll(C));
256
257         ParticleUndoStep *us = (ParticleUndoStep *)us_p;
258         Scene *scene = us->scene_ref.ptr;
259         Object *ob = us->object_ref.ptr;
260         PTCacheEdit *edit = PE_get_current(scene, ob);
261         if (edit) {
262                 undoptcache_to_editcache(&us->data, edit);
263                 DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
264         }
265         else {
266                 BLI_assert(0);
267         }
268 }
269
270 static void particle_undosys_step_free(UndoStep *us_p)
271 {
272         ParticleUndoStep *us = (ParticleUndoStep *)us_p;
273         undoptcache_free_data(&us->data);
274 }
275
276 static void particle_undosys_foreach_ID_ref(
277         UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
278 {
279         ParticleUndoStep *us = (ParticleUndoStep *)us_p;
280         foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->scene_ref));
281         foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->object_ref));
282 }
283
284 /* Export for ED_undo_sys. */
285 void ED_particle_undosys_type(UndoType *ut)
286 {
287         ut->name = "Edit Particle";
288         ut->poll = particle_undosys_poll;
289         ut->step_encode = particle_undosys_step_encode;
290         ut->step_decode = particle_undosys_step_decode;
291         ut->step_free = particle_undosys_step_free;
292
293         ut->step_foreach_ID_ref = particle_undosys_foreach_ID_ref;
294
295         ut->mode = BKE_UNDOTYPE_MODE_STORE;
296         ut->use_context = true;
297
298         ut->step_size = sizeof(ParticleUndoStep);
299 }
300
301 /** \} */