Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / physics / physics_pointcache.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/physics_pointcache.c
29  *  \ingroup edphys
30  */
31
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BLI_blenlib.h"
38 #include "BLI_utildefines.h"
39
40 #include "DNA_scene_types.h"
41
42 #include "BKE_context.h"
43 #include "BKE_screen.h"
44 #include "BKE_global.h"
45 #include "BKE_layer.h"
46 #include "BKE_main.h"
47 #include "BKE_particle.h"
48 #include "BKE_pointcache.h"
49
50 #include "ED_particle.h"
51
52 #include "WM_api.h"
53 #include "WM_types.h"
54
55 #include "RNA_access.h"
56 #include "RNA_define.h"
57
58 #include "physics_intern.h"
59
60 static int ptcache_bake_all_poll(bContext *C)
61 {
62         return CTX_data_scene(C) != NULL;
63 }
64
65 static int ptcache_poll(bContext *C)
66 {
67         PointerRNA ptr= CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
68         return (ptr.data && ptr.id.data);
69 }
70
71 typedef struct PointCacheJob {
72         void *owner;
73         short *stop, *do_update;
74         float *progress;
75
76         PTCacheBaker *baker;
77 } PointCacheJob;
78
79 static void ptcache_job_free(void *customdata)
80 {
81         PointCacheJob *job = customdata;
82         MEM_freeN(job->baker);
83         MEM_freeN(job);
84 }
85
86 static int ptcache_job_break(void *customdata)
87 {
88         PointCacheJob *job = customdata;
89
90         if (G.is_break) {
91                 return 1;
92         }
93
94         if (job->stop && *(job->stop)) {
95                 return 1;
96         }
97
98         return 0;
99 }
100
101 static void ptcache_job_update(void *customdata, float progress, int *cancel)
102 {
103         PointCacheJob *job = customdata;
104
105         if (ptcache_job_break(job)) {
106                 *cancel = 1;
107         }
108
109         *(job->do_update) = true;
110         *(job->progress) = progress;
111 }
112
113 static void ptcache_job_startjob(void *customdata, short *stop, short *do_update, float *progress)
114 {
115         PointCacheJob *job = customdata;
116
117         job->stop = stop;
118         job->do_update = do_update;
119         job->progress = progress;
120
121         G.is_break = false;
122
123         /* XXX annoying hack: needed to prevent data corruption when changing
124          * scene frame in separate threads
125          */
126         G.is_rendering = true;
127         BKE_spacedata_draw_locks(true);
128
129         BKE_ptcache_bake(job->baker);
130
131         *do_update = true;
132         *stop = 0;
133 }
134
135 static void ptcache_job_endjob(void *customdata)
136 {
137         PointCacheJob *job = customdata;
138         Scene *scene = job->baker->scene;
139
140         G.is_rendering = false;
141         BKE_spacedata_draw_locks(false);
142
143         WM_set_locked_interface(G.main->wm.first, false);
144
145         WM_main_add_notifier(NC_SCENE | ND_FRAME, scene);
146         WM_main_add_notifier(NC_OBJECT | ND_POINTCACHE, job->baker->pid.ob);
147 }
148
149 static void ptcache_free_bake(PointCache *cache)
150 {
151         if (cache->edit) {
152                 if (!cache->edit->edited || 1) {// XXX okee("Lose changes done in particle mode?")) {
153                         PE_free_ptcache_edit(cache->edit);
154                         cache->edit = NULL;
155                         cache->flag &= ~PTCACHE_BAKED;
156                 }
157         }
158         else {
159                 cache->flag &= ~PTCACHE_BAKED;
160         }
161 }
162
163 static PTCacheBaker *ptcache_baker_create(bContext *C, wmOperator *op, bool all)
164 {
165         PTCacheBaker *baker = MEM_callocN(sizeof(PTCacheBaker), "PTCacheBaker");
166
167         baker->main = CTX_data_main(C);
168         baker->scene = CTX_data_scene(C);
169         baker->view_layer = CTX_data_view_layer(C);
170         baker->depsgraph = CTX_data_depsgraph(C);
171         baker->bake = RNA_boolean_get(op->ptr, "bake");
172         baker->render = 0;
173         baker->anim_init = 0;
174         baker->quick_step = 1;
175
176         if (!all) {
177                 PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
178                 Object *ob = ptr.id.data;
179                 PointCache *cache = ptr.data;
180                 baker->pid = BKE_ptcache_id_find(ob, baker->scene, cache);
181         }
182
183         return baker;
184 }
185
186 static int ptcache_bake_exec(bContext *C, wmOperator *op)
187 {
188         bool all = STREQ(op->type->idname, "PTCACHE_OT_bake_all");
189
190         PTCacheBaker *baker = ptcache_baker_create(C, op, all);
191         BKE_ptcache_bake(baker);
192         MEM_freeN(baker);
193
194         return OPERATOR_FINISHED;
195 }
196
197 static int ptcache_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
198 {
199         bool all = STREQ(op->type->idname, "PTCACHE_OT_bake_all");
200
201         PointCacheJob *job = MEM_mallocN(sizeof(PointCacheJob), "PointCacheJob");
202         job->baker = ptcache_baker_create(C, op, all);
203         job->baker->bake_job = job;
204         job->baker->update_progress = ptcache_job_update;
205
206         wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_data_scene(C),
207                                     "Point Cache", WM_JOB_PROGRESS, WM_JOB_TYPE_POINTCACHE);
208
209         WM_jobs_customdata_set(wm_job, job, ptcache_job_free);
210         WM_jobs_timer(wm_job, 0.1, NC_OBJECT | ND_POINTCACHE, NC_OBJECT | ND_POINTCACHE);
211         WM_jobs_callbacks(wm_job, ptcache_job_startjob, NULL, NULL, ptcache_job_endjob);
212
213         WM_set_locked_interface(CTX_wm_manager(C), true);
214
215         WM_jobs_start(CTX_wm_manager(C), wm_job);
216
217         WM_event_add_modal_handler(C, op);
218
219         /* we must run modal until the bake job is done, otherwise the undo push
220          * happens before the job ends, which can lead to race conditions between
221          * the baking and file writing code */
222         return OPERATOR_RUNNING_MODAL;
223 }
224
225 static int ptcache_bake_modal(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
226 {
227         Scene *scene = (Scene *) op->customdata;
228
229         /* no running blender, remove handler and pass through */
230         if (0 == WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_POINTCACHE)) {
231                 return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
232         }
233
234         return OPERATOR_PASS_THROUGH;
235 }
236
237 static void ptcache_bake_cancel(bContext *C, wmOperator *op)
238 {
239         wmWindowManager *wm = CTX_wm_manager(C);
240         Scene *scene = (Scene *) op->customdata;
241
242         /* kill on cancel, because job is using op->reports */
243         WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_POINTCACHE);
244 }
245
246 static int ptcache_free_bake_all_exec(bContext *C, wmOperator *UNUSED(op))
247 {
248         Scene *scene = CTX_data_scene(C);
249         PTCacheID *pid;
250         ListBase pidlist;
251
252         FOREACH_SCENE_OBJECT_BEGIN(scene, ob)
253         {
254                 BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR);
255
256                 for (pid = pidlist.first; pid; pid = pid->next) {
257                         ptcache_free_bake(pid->cache);
258                 }
259
260                 BLI_freelistN(&pidlist);
261
262                 WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob);
263         }
264         FOREACH_SCENE_OBJECT_END;
265
266         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
267
268         return OPERATOR_FINISHED;
269 }
270
271 void PTCACHE_OT_bake_all(wmOperatorType *ot)
272 {
273         /* identifiers */
274         ot->name = "Bake All Physics";
275         ot->description = "Bake all physics";
276         ot->idname = "PTCACHE_OT_bake_all";
277
278         /* api callbacks */
279         ot->exec = ptcache_bake_exec;
280         ot->invoke = ptcache_bake_invoke;
281         ot->modal = ptcache_bake_modal;
282         ot->cancel = ptcache_bake_cancel;
283         ot->poll = ptcache_bake_all_poll;
284
285         /* flags */
286         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
287
288         RNA_def_boolean(ot->srna, "bake", 1, "Bake", "");
289 }
290 void PTCACHE_OT_free_bake_all(wmOperatorType *ot)
291 {
292         /* identifiers */
293         ot->name = "Free All Physics Bakes";
294         ot->idname = "PTCACHE_OT_free_bake_all";
295         ot->description = "Free all baked caches of all objects in the current scene";
296
297         /* api callbacks */
298         ot->exec = ptcache_free_bake_all_exec;
299         ot->poll = ptcache_bake_all_poll;
300
301         /* flags */
302         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
303 }
304
305 static int ptcache_free_bake_exec(bContext *C, wmOperator *UNUSED(op))
306 {
307         PointerRNA ptr= CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
308         PointCache *cache= ptr.data;
309         Object *ob= ptr.id.data;
310
311         ptcache_free_bake(cache);
312
313         WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob);
314
315         return OPERATOR_FINISHED;
316 }
317 static int ptcache_bake_from_cache_exec(bContext *C, wmOperator *UNUSED(op))
318 {
319         PointerRNA ptr= CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
320         PointCache *cache= ptr.data;
321         Object *ob= ptr.id.data;
322
323         cache->flag |= PTCACHE_BAKED;
324
325         WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob);
326
327         return OPERATOR_FINISHED;
328 }
329 void PTCACHE_OT_bake(wmOperatorType *ot)
330 {
331         /* identifiers */
332         ot->name = "Bake Physics";
333         ot->description = "Bake physics";
334         ot->idname = "PTCACHE_OT_bake";
335
336         /* api callbacks */
337         ot->exec = ptcache_bake_exec;
338         ot->invoke = ptcache_bake_invoke;
339         ot->modal = ptcache_bake_modal;
340         ot->cancel = ptcache_bake_cancel;
341         ot->poll = ptcache_poll;
342
343         /* flags */
344         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
345
346         RNA_def_boolean(ot->srna, "bake", 0, "Bake", "");
347 }
348 void PTCACHE_OT_free_bake(wmOperatorType *ot)
349 {
350         /* identifiers */
351         ot->name = "Free Physics Bake";
352         ot->description = "Free physics bake";
353         ot->idname = "PTCACHE_OT_free_bake";
354
355         /* api callbacks */
356         ot->exec = ptcache_free_bake_exec;
357         ot->poll = ptcache_poll;
358
359         /* flags */
360         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
361 }
362 void PTCACHE_OT_bake_from_cache(wmOperatorType *ot)
363 {
364         /* identifiers */
365         ot->name = "Bake From Cache";
366         ot->description = "Bake from cache";
367         ot->idname = "PTCACHE_OT_bake_from_cache";
368
369         /* api callbacks */
370         ot->exec = ptcache_bake_from_cache_exec;
371         ot->poll = ptcache_poll;
372
373         /* flags */
374         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
375 }
376
377 static int ptcache_add_new_exec(bContext *C, wmOperator *UNUSED(op))
378 {
379         Scene *scene = CTX_data_scene(C);
380         PointerRNA ptr= CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
381         Object *ob= ptr.id.data;
382         PointCache *cache= ptr.data;
383         PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
384
385         if (pid.cache) {
386                 PointCache *cache_new = BKE_ptcache_add(pid.ptcaches);
387                 cache_new->step = pid.default_step;
388                 *(pid.cache_ptr) = cache_new;
389         }
390
391         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
392         WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob);
393
394         return OPERATOR_FINISHED;
395 }
396 static int ptcache_remove_exec(bContext *C, wmOperator *UNUSED(op))
397 {
398         PointerRNA ptr= CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
399         Scene *scene= CTX_data_scene(C);
400         Object *ob= ptr.id.data;
401         PointCache *cache= ptr.data;
402         PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
403
404         /* don't delete last cache */
405         if (pid.cache && pid.ptcaches->first != pid.ptcaches->last) {
406                 BLI_remlink(pid.ptcaches, pid.cache);
407                 BKE_ptcache_free(pid.cache);
408                 *(pid.cache_ptr) = pid.ptcaches->first;
409         }
410
411         WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob);
412
413         return OPERATOR_FINISHED;
414 }
415 void PTCACHE_OT_add(wmOperatorType *ot)
416 {
417         /* identifiers */
418         ot->name = "Add New Cache";
419         ot->description = "Add new cache";
420         ot->idname = "PTCACHE_OT_add";
421
422         /* api callbacks */
423         ot->exec = ptcache_add_new_exec;
424         ot->poll = ptcache_poll;
425
426         /* flags */
427         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
428 }
429 void PTCACHE_OT_remove(wmOperatorType *ot)
430 {
431         /* identifiers */
432         ot->name = "Delete Current Cache";
433         ot->description = "Delete current cache";
434         ot->idname = "PTCACHE_OT_remove";
435
436         /* api callbacks */
437         ot->exec = ptcache_remove_exec;
438         ot->poll = ptcache_poll;
439
440         /* flags */
441         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
442 }
443