Blender V4.5
physics_fluid.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstdlib>
10#include <cstring>
11#include <sys/stat.h>
12
13#include "MEM_guardedalloc.h"
14
15/* types */
16#include "DNA_object_types.h"
17
18#include "BLI_fileops.h"
19#include "BLI_path_utils.hh"
20#include "BLI_string.h"
21#include "BLI_time.h"
22#include "BLI_utildefines.h"
23
24#include "BLT_translation.hh"
25
26#include "BKE_context.hh"
27#include "BKE_fluid.h"
28#include "BKE_global.hh"
29#include "BKE_main.hh"
30#include "BKE_modifier.hh"
31#include "BKE_report.hh"
32#include "BKE_screen.hh"
33
34#include "DEG_depsgraph.hh"
35
36#include "ED_object.hh"
37#include "ED_screen.hh"
38
39#include "WM_api.hh"
40#include "WM_types.hh"
41
42#include "physics_intern.hh" /* own include */
43
44#include "DNA_fluid_types.h"
45#include "DNA_scene_types.h"
46
47#define FLUID_JOB_BAKE_ALL "FLUID_OT_bake_all"
48#define FLUID_JOB_BAKE_DATA "FLUID_OT_bake_data"
49#define FLUID_JOB_BAKE_NOISE "FLUID_OT_bake_noise"
50#define FLUID_JOB_BAKE_MESH "FLUID_OT_bake_mesh"
51#define FLUID_JOB_BAKE_PARTICLES "FLUID_OT_bake_particles"
52#define FLUID_JOB_BAKE_GUIDES "FLUID_OT_bake_guides"
53#define FLUID_JOB_FREE_ALL "FLUID_OT_free_all"
54#define FLUID_JOB_FREE_DATA "FLUID_OT_free_data"
55#define FLUID_JOB_FREE_NOISE "FLUID_OT_free_noise"
56#define FLUID_JOB_FREE_MESH "FLUID_OT_free_mesh"
57#define FLUID_JOB_FREE_PARTICLES "FLUID_OT_free_particles"
58#define FLUID_JOB_FREE_GUIDES "FLUID_OT_free_guides"
59#define FLUID_JOB_BAKE_PAUSE "FLUID_OT_pause_bake"
60
61struct FluidJob {
62 /* from wmJob */
63 void *owner;
64 bool *stop, *do_update;
65 float *progress;
66 const char *type;
67 const char *name;
68
71 Depsgraph *depsgraph;
73
75
77 double start;
78
80};
81
82static inline bool fluid_is_bake_all(FluidJob *job)
83{
84 return STREQ(job->type, FLUID_JOB_BAKE_ALL);
85}
86static inline bool fluid_is_bake_data(FluidJob *job)
87{
88 return STREQ(job->type, FLUID_JOB_BAKE_DATA);
89}
90static inline bool fluid_is_bake_noise(FluidJob *job)
91{
92 return STREQ(job->type, FLUID_JOB_BAKE_NOISE);
93}
94static inline bool fluid_is_bake_mesh(FluidJob *job)
95{
96 return STREQ(job->type, FLUID_JOB_BAKE_MESH);
97}
98static inline bool fluid_is_bake_particle(FluidJob *job)
99{
100 return STREQ(job->type, FLUID_JOB_BAKE_PARTICLES);
101}
102static inline bool fluid_is_bake_guiding(FluidJob *job)
103{
104 return STREQ(job->type, FLUID_JOB_BAKE_GUIDES);
105}
106static inline bool fluid_is_free_all(FluidJob *job)
107{
108 return STREQ(job->type, FLUID_JOB_FREE_ALL);
109}
110static inline bool fluid_is_free_data(FluidJob *job)
111{
112 return STREQ(job->type, FLUID_JOB_FREE_DATA);
113}
114static inline bool fluid_is_free_noise(FluidJob *job)
115{
116 return STREQ(job->type, FLUID_JOB_FREE_NOISE);
117}
118static inline bool fluid_is_free_mesh(FluidJob *job)
119{
120 return STREQ(job->type, FLUID_JOB_FREE_MESH);
121}
122static inline bool fluid_is_free_particles(FluidJob *job)
123{
124 return STREQ(job->type, FLUID_JOB_FREE_PARTICLES);
125}
126static inline bool fluid_is_free_guiding(FluidJob *job)
127{
128 return STREQ(job->type, FLUID_JOB_FREE_GUIDES);
129}
130
131static bool fluid_initjob(
132 bContext *C, FluidJob *job, wmOperator *op, char *error_msg, int error_size)
133{
134 FluidModifierData *fmd = nullptr;
137
139 if (!fmd) {
140 BLI_strncpy(error_msg, N_("Bake failed: no Fluid modifier found"), error_size);
141 return false;
142 }
143 fds = fmd->domain;
144 if (!fds) {
145 BLI_strncpy(error_msg, N_("Bake failed: invalid domain"), error_size);
146 return false;
147 }
148
149 job->bmain = CTX_data_main(C);
150 job->scene = CTX_data_scene(C);
152 job->ob = ob;
153 job->fmd = fmd;
154 job->type = op->type->idname;
155 job->name = op->type->name;
156
157 return true;
158}
159
161{
162 FluidDomainSettings *fds = job->fmd->domain;
163 char temp_dir[FILE_MAX];
164 temp_dir[0] = '\0';
165 bool is_relative = false;
166
167 const char *relbase = BKE_modifier_path_relbase(job->bmain, job->ob);
168
169 /* We do not accept empty paths, they can end in random places silently, see #51176. */
170 if (fds->cache_directory[0] == '\0') {
171 char cache_name[64];
172 BKE_fluid_cache_new_name_for_current_session(sizeof(cache_name), cache_name);
173 BKE_modifier_path_init(fds->cache_directory, sizeof(fds->cache_directory), cache_name);
176 "Fluid: Empty cache path, reset to default '%s'",
177 fds->cache_directory);
178 }
179
180 BLI_strncpy(temp_dir, fds->cache_directory, FILE_MAXDIR);
181 is_relative = BLI_path_abs(temp_dir, relbase);
182
183 /* Ensure whole path exists */
184 const bool dir_exists = BLI_dir_create_recursive(temp_dir);
185
186 /* We change path to some presumably valid default value, but do not allow bake process to
187 * continue, this gives user chance to set manually another path. */
188 if (!dir_exists) {
189 char cache_name[64];
190 BKE_fluid_cache_new_name_for_current_session(sizeof(cache_name), cache_name);
191 BKE_modifier_path_init(fds->cache_directory, sizeof(fds->cache_directory), cache_name);
192
194 RPT_ERROR,
195 "Fluid: Could not create cache directory '%s', reset to default '%s'",
196 temp_dir,
197 fds->cache_directory);
198
199 /* Ensure whole path exists and is writable. */
200 if (!BLI_dir_create_recursive(temp_dir)) {
202 RPT_ERROR,
203 "Fluid: Could not use default cache directory '%s', "
204 "please define a valid cache path manually",
205 temp_dir);
206 return false;
207 }
208 /* Copy final dir back into domain settings */
209 BLI_strncpy(fds->cache_directory, temp_dir, FILE_MAXDIR);
210
211 return false;
212 }
213
214 /* Change path back to is original state (ie relative or absolute). */
215 if (is_relative) {
216 BLI_path_rel(temp_dir, relbase);
217 }
218
219 /* Copy final dir back into domain settings */
220 BLI_strncpy(fds->cache_directory, temp_dir, FILE_MAXDIR);
221 return true;
222}
223
224static void fluid_bake_free(void *customdata)
225{
226 FluidJob *job = static_cast<FluidJob *>(customdata);
227 MEM_freeN(job);
228}
229
231{
232 FluidDomainSettings *fds = job->fmd->domain;
233 Scene *scene = job->scene;
234 int frame = 1, orig_frame;
235 int frames;
236 int *pause_frame = nullptr;
237 bool is_first_frame;
238
239 frames = fds->cache_frame_end - fds->cache_frame_start + 1;
240
241 if (frames <= 0) {
242 STRNCPY(fds->error, N_("No frames to bake"));
243 return;
244 }
245
246 /* Show progress bar. */
247 if (job->do_update) {
248 *(job->do_update) = true;
249 }
250
251 /* Get current pause frame (pointer) - depending on bake type. */
252 pause_frame = job->pause_frame;
253
254 /* Set frame to start point (depending on current pause frame value). */
255 is_first_frame = ((*pause_frame) == 0);
256 frame = is_first_frame ? fds->cache_frame_start : (*pause_frame);
257
258 /* Save orig frame and update scene frame. */
259 orig_frame = scene->r.cfra;
260 scene->r.cfra = frame;
261
262 /* Loop through selected frames. */
263 for (; frame <= fds->cache_frame_end; frame++) {
264 const float progress = (frame - fds->cache_frame_start) / float(frames);
265
266 /* Keep track of pause frame - needed to init future loop. */
267 (*pause_frame) = frame;
268
269 /* If user requested stop, quit baking. */
270 if (G.is_break) {
271 job->success = 0;
272 return;
273 }
274
275 /* Update progress bar. */
276 if (job->do_update) {
277 *(job->do_update) = true;
278 }
279 if (job->progress) {
280 *(job->progress) = progress;
281 }
282
283 scene->r.cfra = frame;
284
285 /* Update animation system. */
287
288 /* If user requested stop, quit baking. */
289 if (G.is_break) {
290 job->success = 0;
291 return;
292 }
293 }
294
295 /* Restore frame position that we were on before bake. */
296 scene->r.cfra = orig_frame;
297}
298
299static void fluid_bake_endjob(void *customdata)
300{
301 FluidJob *job = static_cast<FluidJob *>(customdata);
302 FluidDomainSettings *fds = job->fmd->domain;
303
304 if (fluid_is_bake_noise(job) || fluid_is_bake_all(job)) {
308 }
309 if (fluid_is_bake_mesh(job) || fluid_is_bake_all(job)) {
313 }
314 if (fluid_is_bake_particle(job) || fluid_is_bake_all(job)) {
318 }
319 if (fluid_is_bake_guiding(job) || fluid_is_bake_all(job)) {
323 }
324 if (fluid_is_bake_data(job) || fluid_is_bake_all(job)) {
328 }
330
331 G.is_rendering = false;
332 WM_set_locked_interface(static_cast<wmWindowManager *>(G_MAIN->wm.first), false);
333
334 /* Bake was successful:
335 * Report for ended bake and how long it took. */
336 if (job->success) {
337 /* Show bake info. */
339 RPT_INFO, "Fluid: %s complete (%.2fs)", job->name, BLI_time_now_seconds() - job->start);
340 }
341 else {
342 if (fds->error[0] != '\0') {
344 RPT_ERROR, "Fluid: %s failed at frame %d: %s", job->name, *job->pause_frame, fds->error);
345 }
346 else { /* User canceled the bake. */
348 RPT_WARNING, "Fluid: %s canceled at frame %d!", job->name, *job->pause_frame);
349 }
350 }
351}
352
353static void fluid_bake_startjob(void *customdata, wmJobWorkerStatus *worker_status)
354{
355 FluidJob *job = static_cast<FluidJob *>(customdata);
356 FluidDomainSettings *fds = job->fmd->domain;
357
358 char temp_dir[FILE_MAX];
359 const char *relbase = BKE_modifier_path_relbase_from_global(job->ob);
360
361 job->stop = &worker_status->stop;
362 job->do_update = &worker_status->do_update;
363 job->progress = &worker_status->progress;
365 job->success = 1;
366
367 G.is_break = false;
368 G.is_rendering = true;
370
371 if (fluid_is_bake_noise(job) || fluid_is_bake_all(job)) {
372 BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE);
373 BLI_path_abs(temp_dir, relbase);
374 BLI_dir_create_recursive(temp_dir); /* Create 'noise' subdir if it does not exist already */
378 }
379 if (fluid_is_bake_mesh(job) || fluid_is_bake_all(job)) {
380 BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_MESH);
381 BLI_path_abs(temp_dir, relbase);
382 BLI_dir_create_recursive(temp_dir); /* Create 'mesh' subdir if it does not exist already */
386 }
387 if (fluid_is_bake_particle(job) || fluid_is_bake_all(job)) {
388 BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES);
389 BLI_path_abs(temp_dir, relbase);
390
391 /* Create 'particles' subdir if it does not exist already */
392 BLI_dir_create_recursive(temp_dir);
393
397 }
398 if (fluid_is_bake_guiding(job) || fluid_is_bake_all(job)) {
399 BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE);
400 BLI_path_abs(temp_dir, relbase);
401 BLI_dir_create_recursive(temp_dir); /* Create 'guiding' subdir if it does not exist already */
405 }
406 if (fluid_is_bake_data(job) || fluid_is_bake_all(job)) {
407 BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_CONFIG);
408 BLI_path_abs(temp_dir, relbase);
409 BLI_dir_create_recursive(temp_dir); /* Create 'config' subdir if it does not exist already */
410
411 BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_DATA);
412 BLI_path_abs(temp_dir, relbase);
413 BLI_dir_create_recursive(temp_dir); /* Create 'data' subdir if it does not exist already */
417
419 BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT);
420 BLI_path_abs(temp_dir, relbase);
421 BLI_dir_create_recursive(temp_dir); /* Create 'script' subdir if it does not exist already */
422 }
423 }
425
427
428 worker_status->do_update = true;
429 worker_status->stop = false;
430}
431
432static void fluid_free_endjob(void *customdata)
433{
434 FluidJob *job = static_cast<FluidJob *>(customdata);
435 FluidDomainSettings *fds = job->fmd->domain;
436
437 G.is_rendering = false;
438 WM_set_locked_interface(static_cast<wmWindowManager *>(G_MAIN->wm.first), false);
439
440 /* Reflect the now empty cache in the viewport too. */
442
443 /* Free was successful:
444 * Report for ended free job and how long it took */
445 if (job->success) {
446 /* Show free job info */
448 RPT_INFO, "Fluid: %s complete (%.2fs)", job->name, BLI_time_now_seconds() - job->start);
449 }
450 else {
451 if (fds->error[0] != '\0') {
453 RPT_ERROR, "Fluid: %s failed at frame %d: %s", job->name, *job->pause_frame, fds->error);
454 }
455 else { /* User canceled the free job */
457 RPT_WARNING, "Fluid: %s canceled at frame %d!", job->name, *job->pause_frame);
458 }
459 }
460}
461
462static void fluid_free_startjob(void *customdata, wmJobWorkerStatus *worker_status)
463{
464 FluidJob *job = static_cast<FluidJob *>(customdata);
465 FluidDomainSettings *fds = job->fmd->domain;
466
467 job->stop = &worker_status->stop;
468 job->do_update = &worker_status->do_update;
469 job->progress = &worker_status->progress;
471 job->success = 1;
472
473 G.is_break = false;
474 G.is_rendering = true;
476
477 int cache_map = 0;
478
479 if (fluid_is_free_data(job) || fluid_is_free_all(job)) {
482 }
483 if (fluid_is_free_noise(job) || fluid_is_free_all(job)) {
484 cache_map |= FLUID_DOMAIN_OUTDATED_NOISE;
485 }
486 if (fluid_is_free_mesh(job) || fluid_is_free_all(job)) {
487 cache_map |= FLUID_DOMAIN_OUTDATED_MESH;
488 }
491 }
492 if (fluid_is_free_guiding(job) || fluid_is_free_all(job)) {
496 }
497#ifdef WITH_FLUID
498 BKE_fluid_cache_free(fds, job->ob, cache_map);
499#else
500 UNUSED_VARS(fds);
501 UNUSED_VARS(cache_map);
502#endif
503
504 worker_status->do_update = true;
505 worker_status->stop = false;
506
507 /* Update scene so that viewport shows freed up scene */
509}
510
511/***************************** Operators ******************************/
512
514{
515 FluidJob *job = MEM_mallocN<FluidJob>("FluidJob");
516 char error_msg[256] = "\0";
517
518 if (!fluid_initjob(C, job, op, error_msg, sizeof(error_msg))) {
519 if (error_msg[0]) {
520 BKE_report(op->reports, RPT_ERROR, error_msg);
521 }
522 fluid_bake_free(job);
523 return OPERATOR_CANCELLED;
524 }
525 if (!fluid_validatepaths(job, op->reports)) {
526 fluid_bake_free(job);
527 return OPERATOR_CANCELLED;
528 }
530
531 wmJobWorkerStatus worker_status = {};
532 fluid_bake_startjob(job, &worker_status);
534 fluid_bake_free(job);
535
536 return OPERATOR_FINISHED;
537}
538
540{
541 Scene *scene = CTX_data_scene(C);
542 FluidJob *job = MEM_mallocN<FluidJob>("FluidJob");
543 char error_msg[256] = "\0";
544
545 if (!fluid_initjob(C, job, op, error_msg, sizeof(error_msg))) {
546 if (error_msg[0]) {
547 BKE_report(op->reports, RPT_ERROR, error_msg);
548 }
549 fluid_bake_free(job);
550 return OPERATOR_CANCELLED;
551 }
552
553 if (!fluid_validatepaths(job, op->reports)) {
554 fluid_bake_free(job);
555 return OPERATOR_CANCELLED;
556 }
557
558 /* Clear existing banners so that the upcoming progress bar from this job has more room. */
560
563 scene,
564 "Fluid Bake",
567
570 WM_jobs_callbacks(wm_job, fluid_bake_startjob, nullptr, nullptr, fluid_bake_endjob);
571
573
576
578}
579
581{
582 /* no running blender, remove handler and pass through */
585 }
586
587 switch (event->type) {
588 case EVT_ESCKEY:
590 default: {
591 break;
592 }
593 }
595}
596
598{
599 FluidModifierData *fmd = nullptr;
602 Scene *scene = CTX_data_scene(C);
603
604 /*
605 * Get modifier data
606 */
608 if (!fmd) {
609 BKE_report(op->reports, RPT_ERROR, "Bake free failed: no Fluid modifier found");
610 return OPERATOR_CANCELLED;
611 }
612 fds = fmd->domain;
613 if (!fds) {
614 BKE_report(op->reports, RPT_ERROR, "Bake free failed: invalid domain");
615 return OPERATOR_CANCELLED;
616 }
617
618 /* Cannot free data if other bakes currently working */
621 {
622 BKE_report(op->reports, RPT_ERROR, "Bake free failed: pending bake jobs found");
623 return OPERATOR_CANCELLED;
624 }
625
626 FluidJob *job = MEM_mallocN<FluidJob>("FluidJob");
627 job->bmain = CTX_data_main(C);
628 job->scene = scene;
630 job->ob = ob;
631 job->fmd = fmd;
632 job->type = op->type->idname;
633 job->name = op->type->name;
634
635 if (!fluid_validatepaths(job, op->reports)) {
636 fluid_bake_free(job);
637 return OPERATOR_CANCELLED;
638 }
639
640 /* Clear existing banners so that the upcoming progress bar from this job has more room. */
642
645 scene,
646 "Fluid Free",
649
652 WM_jobs_callbacks(wm_job, fluid_free_startjob, nullptr, nullptr, fluid_free_endjob);
653
655
656 /* Free Fluid Geometry */
658
659 return OPERATOR_FINISHED;
660}
661
663{
664 FluidModifierData *fmd = nullptr;
667
668 /*
669 * Get modifier data
670 */
672 if (!fmd) {
673 BKE_report(op->reports, RPT_ERROR, "Bake free failed: no Fluid modifier found");
674 return OPERATOR_CANCELLED;
675 }
676 fds = fmd->domain;
677 if (!fds) {
678 BKE_report(op->reports, RPT_ERROR, "Bake free failed: invalid domain");
679 return OPERATOR_CANCELLED;
680 }
681
682 G.is_break = true;
683
684 return OPERATOR_FINISHED;
685}
686
688{
689 /* identifiers */
690 ot->name = "Bake All";
691 ot->description = "Bake Entire Fluid Simulation";
692 ot->idname = FLUID_JOB_BAKE_ALL;
693
694 /* API callbacks. */
695 ot->exec = fluid_bake_exec;
696 ot->invoke = fluid_bake_invoke;
697 ot->modal = fluid_bake_modal;
699}
700
702{
703 /* identifiers */
704 ot->name = "Free All";
705 ot->description = "Free Entire Fluid Simulation";
706 ot->idname = FLUID_JOB_FREE_ALL;
707
708 /* API callbacks. */
709 ot->exec = fluid_free_exec;
711}
712
714{
715 /* identifiers */
716 ot->name = "Bake Data";
717 ot->description = "Bake Fluid Data";
718 ot->idname = FLUID_JOB_BAKE_DATA;
719
720 /* API callbacks. */
721 ot->exec = fluid_bake_exec;
722 ot->invoke = fluid_bake_invoke;
723 ot->modal = fluid_bake_modal;
725}
726
728{
729 /* identifiers */
730 ot->name = "Free Data";
731 ot->description = "Free Fluid Data";
732 ot->idname = FLUID_JOB_FREE_DATA;
733
734 /* API callbacks. */
735 ot->exec = fluid_free_exec;
737}
738
740{
741 /* identifiers */
742 ot->name = "Bake Noise";
743 ot->description = "Bake Fluid Noise";
744 ot->idname = FLUID_JOB_BAKE_NOISE;
745
746 /* API callbacks. */
747 ot->exec = fluid_bake_exec;
748 ot->invoke = fluid_bake_invoke;
749 ot->modal = fluid_bake_modal;
751}
752
754{
755 /* identifiers */
756 ot->name = "Free Noise";
757 ot->description = "Free Fluid Noise";
758 ot->idname = FLUID_JOB_FREE_NOISE;
759
760 /* API callbacks. */
761 ot->exec = fluid_free_exec;
763}
764
766{
767 /* identifiers */
768 ot->name = "Bake Mesh";
769 ot->description = "Bake Fluid Mesh";
770 ot->idname = FLUID_JOB_BAKE_MESH;
771
772 /* API callbacks. */
773 ot->exec = fluid_bake_exec;
774 ot->invoke = fluid_bake_invoke;
775 ot->modal = fluid_bake_modal;
777}
778
780{
781 /* identifiers */
782 ot->name = "Free Mesh";
783 ot->description = "Free Fluid Mesh";
784 ot->idname = FLUID_JOB_FREE_MESH;
785
786 /* API callbacks. */
787 ot->exec = fluid_free_exec;
789}
790
792{
793 /* identifiers */
794 ot->name = "Bake Particles";
795 ot->description = "Bake Fluid Particles";
797
798 /* API callbacks. */
799 ot->exec = fluid_bake_exec;
800 ot->invoke = fluid_bake_invoke;
801 ot->modal = fluid_bake_modal;
803}
804
806{
807 /* identifiers */
808 ot->name = "Free Particles";
809 ot->description = "Free Fluid Particles";
811
812 /* API callbacks. */
813 ot->exec = fluid_free_exec;
815}
816
818{
819 /* identifiers */
820 ot->name = "Bake Guides";
821 ot->description = "Bake Fluid Guiding";
822 ot->idname = FLUID_JOB_BAKE_GUIDES;
823
824 /* API callbacks. */
825 ot->exec = fluid_bake_exec;
826 ot->invoke = fluid_bake_invoke;
827 ot->modal = fluid_bake_modal;
829}
830
832{
833 /* identifiers */
834 ot->name = "Free Guides";
835 ot->description = "Free Fluid Guiding";
836 ot->idname = FLUID_JOB_FREE_GUIDES;
837
838 /* API callbacks. */
839 ot->exec = fluid_free_exec;
841}
842
844{
845 /* identifiers */
846 ot->name = "Pause Bake";
847 ot->description = "Pause Bake";
848 ot->idname = FLUID_JOB_BAKE_PAUSE;
849
850 /* API callbacks. */
851 ot->exec = fluid_pause_exec;
853}
wmWindow * CTX_wm_window(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
void BKE_fluid_cache_new_name_for_current_session(int maxlen, char *r_name)
Definition fluid.cc:5060
void BKE_fluid_cache_free(struct FluidDomainSettings *fds, struct Object *ob, int cache_map)
#define G_MAIN
void BKE_modifier_path_init(char *path, int path_maxncpy, const char *name)
ModifierData * BKE_modifiers_findby_type(const Object *ob, ModifierType type)
const char * BKE_modifier_path_relbase_from_global(Object *ob)
const char * BKE_modifier_path_relbase(Main *bmain, Object *ob)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
void BKE_spacedata_draw_locks(ARegionDrawLockFlags lock_flags)
Definition screen.cc:417
@ REGION_DRAW_LOCK_BAKING
File and directory operations.
bool BLI_dir_create_recursive(const char *dirname) ATTR_NONNULL()
Definition fileops_c.cc:391
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
#define FILE_MAX
#define BLI_path_join(...)
bool void BLI_path_rel(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1)
#define FILE_MAXDIR
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.cc:65
#define UNUSED_VARS(...)
#define STREQ(a, b)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
#define FLUID_DOMAIN_DIR_DATA
#define FLUID_DOMAIN_DIR_PARTICLES
@ FLUID_DOMAIN_EXPORT_MANTA_SCRIPT
#define FLUID_DOMAIN_DIR_MESH
#define FLUID_DOMAIN_DIR_GUIDE
#define FLUID_DOMAIN_DIR_SCRIPT
@ FLUID_DOMAIN_BAKED_DATA
@ FLUID_DOMAIN_OUTDATED_GUIDE
@ FLUID_DOMAIN_OUTDATED_PARTICLES
@ FLUID_DOMAIN_BAKING_MESH
@ FLUID_DOMAIN_BAKING_NOISE
@ FLUID_DOMAIN_BAKING_GUIDE
@ FLUID_DOMAIN_OUTDATED_NOISE
@ FLUID_DOMAIN_BAKED_NOISE
@ FLUID_DOMAIN_BAKED_MESH
@ FLUID_DOMAIN_OUTDATED_MESH
@ FLUID_DOMAIN_BAKING_DATA
@ FLUID_DOMAIN_BAKED_GUIDE
@ FLUID_DOMAIN_BAKED_PARTICLES
@ FLUID_DOMAIN_OUTDATED_DATA
@ FLUID_DOMAIN_BAKING_PARTICLES
#define FLUID_DOMAIN_DIR_CONFIG
#define FLUID_DOMAIN_DIR_NOISE
@ eModifierType_Fluid
Object is a sort of wrapper for general info.
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
bool ED_operator_object_active_editable(bContext *C)
void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
@ WM_JOB_TYPE_OBJECT_SIM_FLUID
Definition WM_api.hh:1733
@ WM_JOB_PROGRESS
Definition WM_api.hh:1716
#define ND_MODIFIER
Definition WM_types.hh:459
ReportList * reports
Definition WM_types.hh:1025
float progress
Definition WM_types.hh:1019
#define NC_OBJECT
Definition WM_types.hh:376
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define G(x, y, z)
Object * context_active_object(const bContext *C)
#define FLUID_JOB_FREE_DATA
#define FLUID_JOB_BAKE_GUIDES
#define FLUID_JOB_BAKE_ALL
void FLUID_OT_free_mesh(wmOperatorType *ot)
static void fluid_bake_endjob(void *customdata)
static bool fluid_is_bake_guiding(FluidJob *job)
static bool fluid_is_bake_particle(FluidJob *job)
static bool fluid_is_free_data(FluidJob *job)
static wmOperatorStatus fluid_pause_exec(bContext *C, wmOperator *op)
static bool fluid_is_bake_noise(FluidJob *job)
static bool fluid_validatepaths(FluidJob *job, ReportList *reports)
#define FLUID_JOB_FREE_MESH
void FLUID_OT_free_particles(wmOperatorType *ot)
#define FLUID_JOB_FREE_ALL
void FLUID_OT_free_all(wmOperatorType *ot)
static wmOperatorStatus fluid_bake_invoke(bContext *C, wmOperator *op, const wmEvent *)
void FLUID_OT_bake_guides(wmOperatorType *ot)
static void fluid_free_startjob(void *customdata, wmJobWorkerStatus *worker_status)
static wmOperatorStatus fluid_free_exec(bContext *C, wmOperator *op)
static wmOperatorStatus fluid_bake_modal(bContext *C, wmOperator *, const wmEvent *event)
static bool fluid_is_free_mesh(FluidJob *job)
void FLUID_OT_free_guides(wmOperatorType *ot)
#define FLUID_JOB_BAKE_PAUSE
void FLUID_OT_bake_particles(wmOperatorType *ot)
static bool fluid_initjob(bContext *C, FluidJob *job, wmOperator *op, char *error_msg, int error_size)
static void fluid_free_endjob(void *customdata)
static bool fluid_is_free_guiding(FluidJob *job)
static bool fluid_is_bake_all(FluidJob *job)
static wmOperatorStatus fluid_bake_exec(bContext *C, wmOperator *op)
static void fluid_bake_free(void *customdata)
#define FLUID_JOB_BAKE_NOISE
#define FLUID_JOB_FREE_PARTICLES
void FLUID_OT_bake_all(wmOperatorType *ot)
#define FLUID_JOB_BAKE_PARTICLES
static bool fluid_is_bake_mesh(FluidJob *job)
static void fluid_bake_startjob(void *customdata, wmJobWorkerStatus *worker_status)
static bool fluid_is_free_all(FluidJob *job)
static bool fluid_is_free_noise(FluidJob *job)
static bool fluid_is_free_particles(FluidJob *job)
#define FLUID_JOB_FREE_NOISE
void FLUID_OT_bake_data(wmOperatorType *ot)
static bool fluid_is_bake_data(FluidJob *job)
void FLUID_OT_free_noise(wmOperatorType *ot)
#define FLUID_JOB_FREE_GUIDES
#define FLUID_JOB_BAKE_DATA
void FLUID_OT_pause_bake(wmOperatorType *ot)
void FLUID_OT_bake_noise(wmOperatorType *ot)
void FLUID_OT_free_data(wmOperatorType *ot)
#define FLUID_JOB_BAKE_MESH
static void fluid_bake_sequence(FluidJob *job)
void FLUID_OT_bake_mesh(wmOperatorType *ot)
int * pause_frame
bool * stop
const char * name
FluidModifierData * fmd
Main * bmain
Object * ob
Depsgraph * depsgraph
const char * type
double start
float * progress
bool * do_update
void * owner
Scene * scene
struct FluidDomainSettings * domain
struct RenderData r
wmEventType type
Definition WM_types.hh:754
const char * name
Definition WM_types.hh:1030
const char * idname
Definition WM_types.hh:1032
struct ReportList * reports
struct wmOperatorType * type
#define N_(msgid)
void WM_report_banners_cancel(Main *bmain)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_set_locked_interface_with_flags(wmWindowManager *wm, short lock_flags)
void WM_global_reportf(eReportType type, const char *format,...)
void WM_set_locked_interface(wmWindowManager *wm, bool lock)
@ EVT_ESCKEY
wmOperatorType * ot
Definition wm_files.cc:4226
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
Definition wm_jobs.cc:353
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:456
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, const char *name, const eWM_JobFlag flag, const eWM_JobType job_type)
Definition wm_jobs.cc:190
void WM_jobs_callbacks(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *))
Definition wm_jobs.cc:365
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:224
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:337