Blender V5.0
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_string_utf8.h"
22#include "BLI_time.h"
23#include "BLI_utildefines.h"
24
25#include "BLT_translation.hh"
26
27#include "BKE_context.hh"
28#include "BKE_fluid.h"
29#include "BKE_global.hh"
30#include "BKE_main.hh"
31#include "BKE_modifier.hh"
32#include "BKE_report.hh"
33#include "BKE_screen.hh"
34
35#include "DEG_depsgraph.hh"
36
37#include "ED_object.hh"
38#include "ED_screen.hh"
39
40#include "WM_api.hh"
41#include "WM_types.hh"
42
43#include "physics_intern.hh" /* own include */
44
45#include "DNA_fluid_types.h"
46#include "DNA_scene_types.h"
47
48#define FLUID_JOB_BAKE_ALL "FLUID_OT_bake_all"
49#define FLUID_JOB_BAKE_DATA "FLUID_OT_bake_data"
50#define FLUID_JOB_BAKE_NOISE "FLUID_OT_bake_noise"
51#define FLUID_JOB_BAKE_MESH "FLUID_OT_bake_mesh"
52#define FLUID_JOB_BAKE_PARTICLES "FLUID_OT_bake_particles"
53#define FLUID_JOB_BAKE_GUIDES "FLUID_OT_bake_guides"
54#define FLUID_JOB_FREE_ALL "FLUID_OT_free_all"
55#define FLUID_JOB_FREE_DATA "FLUID_OT_free_data"
56#define FLUID_JOB_FREE_NOISE "FLUID_OT_free_noise"
57#define FLUID_JOB_FREE_MESH "FLUID_OT_free_mesh"
58#define FLUID_JOB_FREE_PARTICLES "FLUID_OT_free_particles"
59#define FLUID_JOB_FREE_GUIDES "FLUID_OT_free_guides"
60#define FLUID_JOB_BAKE_PAUSE "FLUID_OT_pause_bake"
61
62struct FluidJob {
63 /* from wmJob */
64 void *owner;
65 bool *stop, *do_update;
66 float *progress;
67 const char *type;
68 const char *name;
69
72 Depsgraph *depsgraph;
74
76
78 double start;
79
81};
82
83static inline bool fluid_is_bake_all(FluidJob *job)
84{
85 return STREQ(job->type, FLUID_JOB_BAKE_ALL);
86}
87static inline bool fluid_is_bake_data(FluidJob *job)
88{
89 return STREQ(job->type, FLUID_JOB_BAKE_DATA);
90}
91static inline bool fluid_is_bake_noise(FluidJob *job)
92{
93 return STREQ(job->type, FLUID_JOB_BAKE_NOISE);
94}
95static inline bool fluid_is_bake_mesh(FluidJob *job)
96{
97 return STREQ(job->type, FLUID_JOB_BAKE_MESH);
98}
99static inline bool fluid_is_bake_particle(FluidJob *job)
100{
101 return STREQ(job->type, FLUID_JOB_BAKE_PARTICLES);
102}
103static inline bool fluid_is_bake_guiding(FluidJob *job)
104{
105 return STREQ(job->type, FLUID_JOB_BAKE_GUIDES);
106}
107static inline bool fluid_is_free_all(FluidJob *job)
108{
109 return STREQ(job->type, FLUID_JOB_FREE_ALL);
110}
111static inline bool fluid_is_free_data(FluidJob *job)
112{
113 return STREQ(job->type, FLUID_JOB_FREE_DATA);
114}
115static inline bool fluid_is_free_noise(FluidJob *job)
116{
117 return STREQ(job->type, FLUID_JOB_FREE_NOISE);
118}
119static inline bool fluid_is_free_mesh(FluidJob *job)
120{
121 return STREQ(job->type, FLUID_JOB_FREE_MESH);
122}
123static inline bool fluid_is_free_particles(FluidJob *job)
124{
125 return STREQ(job->type, FLUID_JOB_FREE_PARTICLES);
126}
127static inline bool fluid_is_free_guiding(FluidJob *job)
128{
129 return STREQ(job->type, FLUID_JOB_FREE_GUIDES);
130}
131
132static bool fluid_initjob(
133 bContext *C, FluidJob *job, wmOperator *op, char *error_msg, int error_size)
134{
135 FluidModifierData *fmd = nullptr;
138
140 if (!fmd) {
141 BLI_strncpy_utf8(error_msg, N_("Bake failed: no Fluid modifier found"), error_size);
142 return false;
143 }
144 fds = fmd->domain;
145 if (!fds) {
146 BLI_strncpy_utf8(error_msg, N_("Bake failed: invalid domain"), error_size);
147 return false;
148 }
149
150 job->bmain = CTX_data_main(C);
151 job->scene = CTX_data_scene(C);
153 job->ob = ob;
154 job->fmd = fmd;
155 job->type = op->type->idname;
156 job->name = op->type->name;
157
158 return true;
159}
160
161static bool fluid_validatepaths(FluidJob *job, ReportList *reports)
162{
163 FluidDomainSettings *fds = job->fmd->domain;
164 char temp_dir[FILE_MAX];
165 temp_dir[0] = '\0';
166 bool is_relative = false;
167
168 const char *relbase = BKE_modifier_path_relbase(job->bmain, job->ob);
169
170 /* We do not accept empty paths, they can end in random places silently, see #51176. */
171 if (fds->cache_directory[0] == '\0') {
172 char cache_name[64];
173 BKE_fluid_cache_new_name_for_current_session(sizeof(cache_name), cache_name);
174 BKE_modifier_path_init(fds->cache_directory, sizeof(fds->cache_directory), cache_name);
175 BKE_reportf(reports,
177 "Fluid: Empty cache path, reset to default '%s'",
178 fds->cache_directory);
179 }
180
181 BLI_strncpy(temp_dir, fds->cache_directory, FILE_MAXDIR);
182 is_relative = BLI_path_abs(temp_dir, relbase);
183
184 /* Ensure whole path exists */
185 const bool dir_exists = BLI_dir_create_recursive(temp_dir);
186
187 /* We change path to some presumably valid default value, but do not allow bake process to
188 * continue, this gives user chance to set manually another path. */
189 if (!dir_exists) {
190 char cache_name[64];
191 BKE_fluid_cache_new_name_for_current_session(sizeof(cache_name), cache_name);
192 BKE_modifier_path_init(fds->cache_directory, sizeof(fds->cache_directory), cache_name);
193
194 BKE_reportf(reports,
195 RPT_ERROR,
196 "Fluid: Could not create cache directory '%s', reset to default '%s'",
197 temp_dir,
198 fds->cache_directory);
199
200 /* Ensure whole path exists and is writable. */
201 if (!BLI_dir_create_recursive(temp_dir)) {
202 BKE_reportf(reports,
203 RPT_ERROR,
204 "Fluid: Could not use default cache directory '%s', "
205 "please define a valid cache path manually",
206 temp_dir);
207 return false;
208 }
209 /* Copy final dir back into domain settings */
210 BLI_strncpy(fds->cache_directory, temp_dir, FILE_MAXDIR);
211
212 return false;
213 }
214
215 /* Change path back to is original state (ie relative or absolute). */
216 if (is_relative) {
217 BLI_path_rel(temp_dir, relbase);
218 }
219
220 /* Copy final dir back into domain settings */
221 BLI_strncpy(fds->cache_directory, temp_dir, FILE_MAXDIR);
222 return true;
223}
224
225static void fluid_bake_free(void *customdata)
226{
227 FluidJob *job = static_cast<FluidJob *>(customdata);
228 MEM_freeN(job);
229}
230
232{
233 FluidDomainSettings *fds = job->fmd->domain;
234 Scene *scene = job->scene;
235 int frame = 1, orig_frame;
236 int frames;
237 int *pause_frame = nullptr;
238 bool is_first_frame;
239
240 frames = fds->cache_frame_end - fds->cache_frame_start + 1;
241
242 if (frames <= 0) {
243 STRNCPY_UTF8(fds->error, N_("No frames to bake"));
244 return;
245 }
246
247 /* Show progress bar. */
248 if (job->do_update) {
249 *(job->do_update) = true;
250 }
251
252 /* Get current pause frame (pointer) - depending on bake type. */
253 pause_frame = job->pause_frame;
254
255 /* Set frame to start point (depending on current pause frame value). */
256 is_first_frame = ((*pause_frame) == 0);
257 frame = is_first_frame ? fds->cache_frame_start : (*pause_frame);
258
259 /* Save orig frame and update scene frame. */
260 orig_frame = scene->r.cfra;
261 scene->r.cfra = frame;
262
263 /* Loop through selected frames. */
264 for (; frame <= fds->cache_frame_end; frame++) {
265 const float progress = (frame - fds->cache_frame_start) / float(frames);
266
267 /* Keep track of pause frame - needed to init future loop. */
268 (*pause_frame) = frame;
269
270 /* If user requested stop, quit baking. */
271 if (G.is_break) {
272 job->success = 0;
273 return;
274 }
275
276 /* Update progress bar. */
277 if (job->do_update) {
278 *(job->do_update) = true;
279 }
280 if (job->progress) {
281 *(job->progress) = progress;
282 }
283
284 scene->r.cfra = frame;
285
286 /* Update animation system. */
288
289 /* If user requested stop, quit baking. */
290 if (G.is_break) {
291 job->success = 0;
292 return;
293 }
294 }
295
296 /* Restore frame position that we were on before bake. */
297 scene->r.cfra = orig_frame;
298}
299
300static void fluid_bake_endjob(void *customdata)
301{
302 FluidJob *job = static_cast<FluidJob *>(customdata);
303 FluidDomainSettings *fds = job->fmd->domain;
304
305 if (fluid_is_bake_noise(job) || fluid_is_bake_all(job)) {
309 }
310 if (fluid_is_bake_mesh(job) || fluid_is_bake_all(job)) {
314 }
315 if (fluid_is_bake_particle(job) || fluid_is_bake_all(job)) {
319 }
320 if (fluid_is_bake_guiding(job) || fluid_is_bake_all(job)) {
324 }
325 if (fluid_is_bake_data(job) || fluid_is_bake_all(job)) {
329 }
331
332 G.is_rendering = false;
333 WM_locked_interface_set(static_cast<wmWindowManager *>(G_MAIN->wm.first), false);
334
335 /* Bake was successful:
336 * Report for ended bake and how long it took. */
337 if (job->success) {
338 /* Show bake info. */
340 "Fluid: %s complete (%.2fs)",
342 BLI_time_now_seconds() - job->start);
343 }
344 else {
345 if (fds->error[0] != '\0') {
347 "Fluid: %s failed at frame %d: %s",
349 *job->pause_frame,
350 fds->error);
351 }
352 else { /* User canceled the bake. */
354 "Fluid: %s canceled at frame %d!",
356 *job->pause_frame);
357 }
358 }
359}
360
361static void fluid_bake_startjob(void *customdata, wmJobWorkerStatus *worker_status)
362{
363 FluidJob *job = static_cast<FluidJob *>(customdata);
364 FluidDomainSettings *fds = job->fmd->domain;
365
366 char temp_dir[FILE_MAX];
367 const char *relbase = BKE_modifier_path_relbase_from_global(job->ob);
368
369 job->stop = &worker_status->stop;
370 job->do_update = &worker_status->do_update;
371 job->progress = &worker_status->progress;
373 job->success = 1;
374
375 G.is_break = false;
376 G.is_rendering = true;
378
379 if (fluid_is_bake_noise(job) || fluid_is_bake_all(job)) {
380 BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE);
381 BLI_path_abs(temp_dir, relbase);
382 BLI_dir_create_recursive(temp_dir); /* Create 'noise' subdir if it does not exist already */
386 }
387 if (fluid_is_bake_mesh(job) || fluid_is_bake_all(job)) {
388 BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_MESH);
389 BLI_path_abs(temp_dir, relbase);
390 BLI_dir_create_recursive(temp_dir); /* Create 'mesh' subdir if it does not exist already */
394 }
395 if (fluid_is_bake_particle(job) || fluid_is_bake_all(job)) {
396 BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES);
397 BLI_path_abs(temp_dir, relbase);
398
399 /* Create 'particles' subdir if it does not exist already */
400 BLI_dir_create_recursive(temp_dir);
401
405 }
406 if (fluid_is_bake_guiding(job) || fluid_is_bake_all(job)) {
407 BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE);
408 BLI_path_abs(temp_dir, relbase);
409 BLI_dir_create_recursive(temp_dir); /* Create 'guiding' subdir if it does not exist already */
413 }
414 if (fluid_is_bake_data(job) || fluid_is_bake_all(job)) {
415 BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_CONFIG);
416 BLI_path_abs(temp_dir, relbase);
417 BLI_dir_create_recursive(temp_dir); /* Create 'config' subdir if it does not exist already */
418
419 BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_DATA);
420 BLI_path_abs(temp_dir, relbase);
421 BLI_dir_create_recursive(temp_dir); /* Create 'data' subdir if it does not exist already */
425
427 BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT);
428 BLI_path_abs(temp_dir, relbase);
429 BLI_dir_create_recursive(temp_dir); /* Create 'script' subdir if it does not exist already */
430 }
431 }
433
435
436 worker_status->do_update = true;
437 worker_status->stop = false;
438}
439
440static void fluid_free_endjob(void *customdata)
441{
442 FluidJob *job = static_cast<FluidJob *>(customdata);
443 FluidDomainSettings *fds = job->fmd->domain;
444
445 G.is_rendering = false;
446 WM_locked_interface_set(static_cast<wmWindowManager *>(G_MAIN->wm.first), false);
447
448 /* Reflect the now empty cache in the viewport too. */
450
451 /* Free was successful:
452 * Report for ended free job and how long it took */
453 if (job->success) {
454 /* Show free job info */
456 "Fluid: %s complete (%.2fs)",
458 BLI_time_now_seconds() - job->start);
459 }
460 else {
461 if (fds->error[0] != '\0') {
463 "Fluid: %s failed at frame %d: %s",
465 *job->pause_frame,
466 fds->error);
467 }
468 else { /* User canceled the free job */
470 "Fluid: %s canceled at frame %d!",
472 *job->pause_frame);
473 }
474 }
475}
476
477static void fluid_free_startjob(void *customdata, wmJobWorkerStatus *worker_status)
478{
479 FluidJob *job = static_cast<FluidJob *>(customdata);
480 FluidDomainSettings *fds = job->fmd->domain;
481
482 job->stop = &worker_status->stop;
483 job->do_update = &worker_status->do_update;
484 job->progress = &worker_status->progress;
486 job->success = 1;
487
488 G.is_break = false;
489 G.is_rendering = true;
491
492 int cache_map = 0;
493
494 if (fluid_is_free_data(job) || fluid_is_free_all(job)) {
497 }
498 if (fluid_is_free_noise(job) || fluid_is_free_all(job)) {
499 cache_map |= FLUID_DOMAIN_OUTDATED_NOISE;
500 }
501 if (fluid_is_free_mesh(job) || fluid_is_free_all(job)) {
502 cache_map |= FLUID_DOMAIN_OUTDATED_MESH;
503 }
506 }
507 if (fluid_is_free_guiding(job) || fluid_is_free_all(job)) {
511 }
512#ifdef WITH_FLUID
513 BKE_fluid_cache_free(fds, job->ob, cache_map);
514#else
515 UNUSED_VARS(fds);
516 UNUSED_VARS(cache_map);
517#endif
518
519 worker_status->do_update = true;
520 worker_status->stop = false;
521
522 /* Update scene so that viewport shows freed up scene */
524}
525
526/***************************** Operators ******************************/
527
529{
530 FluidJob *job = MEM_mallocN<FluidJob>("FluidJob");
531 char error_msg[256] = "\0";
532
533 if (!fluid_initjob(C, job, op, error_msg, sizeof(error_msg))) {
534 if (error_msg[0]) {
535 BKE_report(op->reports, RPT_ERROR, error_msg);
536 }
537 fluid_bake_free(job);
538 return OPERATOR_CANCELLED;
539 }
540 if (!fluid_validatepaths(job, op->reports)) {
541 fluid_bake_free(job);
542 return OPERATOR_CANCELLED;
543 }
545
546 wmJobWorkerStatus worker_status = {};
547 fluid_bake_startjob(job, &worker_status);
549 fluid_bake_free(job);
550
551 return OPERATOR_FINISHED;
552}
553
555{
556 Scene *scene = CTX_data_scene(C);
557 FluidJob *job = MEM_mallocN<FluidJob>("FluidJob");
558 char error_msg[256] = "\0";
559
560 if (!fluid_initjob(C, job, op, error_msg, sizeof(error_msg))) {
561 if (error_msg[0]) {
562 BKE_report(op->reports, RPT_ERROR, error_msg);
563 }
564 fluid_bake_free(job);
565 return OPERATOR_CANCELLED;
566 }
567
568 if (!fluid_validatepaths(job, op->reports)) {
569 fluid_bake_free(job);
570 return OPERATOR_CANCELLED;
571 }
572
573 /* Clear existing banners so that the upcoming progress bar from this job has more room. */
575
578 scene,
579 "Baking fluid...",
582
585 WM_jobs_callbacks(wm_job, fluid_bake_startjob, nullptr, nullptr, fluid_bake_endjob);
586
588
591
593}
594
596{
597 /* no running blender, remove handler and pass through */
600 }
601
602 switch (event->type) {
603 case EVT_ESCKEY:
605 default: {
606 break;
607 }
608 }
610}
611
613{
614 FluidModifierData *fmd = nullptr;
617 Scene *scene = CTX_data_scene(C);
618
619 /*
620 * Get modifier data
621 */
623 if (!fmd) {
624 BKE_report(op->reports, RPT_ERROR, "Bake free failed: no Fluid modifier found");
625 return OPERATOR_CANCELLED;
626 }
627 fds = fmd->domain;
628 if (!fds) {
629 BKE_report(op->reports, RPT_ERROR, "Bake free failed: invalid domain");
630 return OPERATOR_CANCELLED;
631 }
632
633 /* Cannot free data if other bakes currently working */
636 {
637 BKE_report(op->reports, RPT_ERROR, "Bake free failed: pending bake jobs found");
638 return OPERATOR_CANCELLED;
639 }
640
641 FluidJob *job = MEM_mallocN<FluidJob>("FluidJob");
642 job->bmain = CTX_data_main(C);
643 job->scene = scene;
645 job->ob = ob;
646 job->fmd = fmd;
647 job->type = op->type->idname;
648 job->name = op->type->name;
649
650 if (!fluid_validatepaths(job, op->reports)) {
651 fluid_bake_free(job);
652 return OPERATOR_CANCELLED;
653 }
654
655 /* Clear existing banners so that the upcoming progress bar from this job has more room. */
657
660 scene,
661 "Freeing fluid...",
664
667 WM_jobs_callbacks(wm_job, fluid_free_startjob, nullptr, nullptr, fluid_free_endjob);
668
670
671 /* Free Fluid Geometry. */
673
674 return OPERATOR_FINISHED;
675}
676
678{
679 FluidModifierData *fmd = nullptr;
682
683 /*
684 * Get modifier data
685 */
687 if (!fmd) {
688 BKE_report(op->reports, RPT_ERROR, "Bake free failed: no Fluid modifier found");
689 return OPERATOR_CANCELLED;
690 }
691 fds = fmd->domain;
692 if (!fds) {
693 BKE_report(op->reports, RPT_ERROR, "Bake free failed: invalid domain");
694 return OPERATOR_CANCELLED;
695 }
696
697 G.is_break = true;
698
699 return OPERATOR_FINISHED;
700}
701
703{
704 /* identifiers */
705 ot->name = "Bake All";
706 ot->description = "Bake Entire Fluid Simulation";
707 ot->idname = FLUID_JOB_BAKE_ALL;
708
709 /* API callbacks. */
710 ot->exec = fluid_bake_exec;
711 ot->invoke = fluid_bake_invoke;
712 ot->modal = fluid_bake_modal;
714}
715
717{
718 /* identifiers */
719 ot->name = "Free All";
720 ot->description = "Free Entire Fluid Simulation";
721 ot->idname = FLUID_JOB_FREE_ALL;
722
723 /* API callbacks. */
724 ot->exec = fluid_free_exec;
726}
727
729{
730 /* identifiers */
731 ot->name = "Bake Data";
732 ot->description = "Bake Fluid Data";
733 ot->idname = FLUID_JOB_BAKE_DATA;
734
735 /* API callbacks. */
736 ot->exec = fluid_bake_exec;
737 ot->invoke = fluid_bake_invoke;
738 ot->modal = fluid_bake_modal;
740}
741
743{
744 /* identifiers */
745 ot->name = "Free Data";
746 ot->description = "Free Fluid Data";
747 ot->idname = FLUID_JOB_FREE_DATA;
748
749 /* API callbacks. */
750 ot->exec = fluid_free_exec;
752}
753
755{
756 /* identifiers */
757 ot->name = "Bake Noise";
758 ot->description = "Bake Fluid Noise";
759 ot->idname = FLUID_JOB_BAKE_NOISE;
760
761 /* API callbacks. */
762 ot->exec = fluid_bake_exec;
763 ot->invoke = fluid_bake_invoke;
764 ot->modal = fluid_bake_modal;
766}
767
769{
770 /* identifiers */
771 ot->name = "Free Noise";
772 ot->description = "Free Fluid Noise";
773 ot->idname = FLUID_JOB_FREE_NOISE;
774
775 /* API callbacks. */
776 ot->exec = fluid_free_exec;
778}
779
781{
782 /* identifiers */
783 ot->name = "Bake Mesh";
784 ot->description = "Bake Fluid Mesh";
785 ot->idname = FLUID_JOB_BAKE_MESH;
786
787 /* API callbacks. */
788 ot->exec = fluid_bake_exec;
789 ot->invoke = fluid_bake_invoke;
790 ot->modal = fluid_bake_modal;
792}
793
795{
796 /* identifiers */
797 ot->name = "Free Mesh";
798 ot->description = "Free Fluid Mesh";
799 ot->idname = FLUID_JOB_FREE_MESH;
800
801 /* API callbacks. */
802 ot->exec = fluid_free_exec;
804}
805
807{
808 /* identifiers */
809 ot->name = "Bake Particles";
810 ot->description = "Bake Fluid Particles";
812
813 /* API callbacks. */
814 ot->exec = fluid_bake_exec;
815 ot->invoke = fluid_bake_invoke;
816 ot->modal = fluid_bake_modal;
818}
819
821{
822 /* identifiers */
823 ot->name = "Free Particles";
824 ot->description = "Free Fluid Particles";
826
827 /* API callbacks. */
828 ot->exec = fluid_free_exec;
830}
831
833{
834 /* identifiers */
835 ot->name = "Bake Guides";
836 ot->description = "Bake Fluid Guiding";
837 ot->idname = FLUID_JOB_BAKE_GUIDES;
838
839 /* API callbacks. */
840 ot->exec = fluid_bake_exec;
841 ot->invoke = fluid_bake_invoke;
842 ot->modal = fluid_bake_modal;
844}
845
847{
848 /* identifiers */
849 ot->name = "Free Guides";
850 ot->description = "Free Fluid Guiding";
851 ot->idname = FLUID_JOB_FREE_GUIDES;
852
853 /* API callbacks. */
854 ot->exec = fluid_free_exec;
856}
857
859{
860 /* identifiers */
861 ot->name = "Pause Bake";
862 ot->description = "Pause Bake";
863 ot->idname = FLUID_JOB_BAKE_PAUSE;
864
865 /* API callbacks. */
866 ot->exec = fluid_pause_exec;
868}
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:5074
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
@ RPT_INFO
Definition BKE_report.hh:35
@ RPT_ERROR
Definition BKE_report.hh:39
@ RPT_WARNING
Definition BKE_report.hh:38
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
void BKE_spacedata_draw_locks(ARegionDrawLockFlags lock_flags)
Definition screen.cc:423
@ REGION_DRAW_LOCK_BAKING
File and directory operations.
bool BLI_dir_create_recursive(const char *dirname) ATTR_NONNULL()
Definition fileops_c.cc:414
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 * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
char * BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define STRNCPY_UTF8(dst, src)
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.cc:113
#define UNUSED_VARS(...)
#define STREQ(a, b)
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT
#define CTX_RPT_(context, msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
#define FLUID_DOMAIN_DIR_DATA
#define FLUID_DOMAIN_DIR_PARTICLES
#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
@ FLUID_DOMAIN_EXPORT_MANTA_SCRIPT
@ 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:1783
@ WM_JOB_PROGRESS
Definition WM_api.hh:1766
#define ND_MODIFIER
Definition WM_types.hh:462
#define NC_OBJECT
Definition WM_types.hh:379
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:757
const char * name
Definition WM_types.hh:1033
const char * idname
Definition WM_types.hh:1035
struct ReportList * reports
struct wmOperatorType * type
#define N_(msgid)
void WM_locked_interface_set(wmWindowManager *wm, bool lock)
void WM_report_banners_cancel(Main *bmain)
void WM_locked_interface_set_with_flags(wmWindowManager *wm, short lock_flags)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_global_reportf(eReportType type, const char *format,...)
@ EVT_ESCKEY
wmOperatorType * ot
Definition wm_files.cc:4237
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
Definition wm_jobs.cc:376
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:479
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:211
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:388
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:247
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:360