Blender  V2.93
physics_fluid.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) Blender Foundation
17  * All rights reserved.
18  */
19 
24 #include <math.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/stat.h>
28 
29 #include "MEM_guardedalloc.h"
30 
31 /* types */
32 #include "DNA_action_types.h"
33 #include "DNA_object_types.h"
34 
35 #include "BLI_blenlib.h"
36 #include "BLI_path_util.h"
37 #include "BLI_utildefines.h"
38 
39 #include "BLT_translation.h"
40 
41 #include "BKE_context.h"
42 #include "BKE_fluid.h"
43 #include "BKE_global.h"
44 #include "BKE_main.h"
45 #include "BKE_modifier.h"
46 #include "BKE_report.h"
47 #include "BKE_screen.h"
48 
49 #include "DEG_depsgraph.h"
50 
51 #include "ED_object.h"
52 #include "ED_screen.h"
53 #include "PIL_time.h"
54 
55 #include "WM_api.h"
56 #include "WM_types.h"
57 
58 #include "physics_intern.h" /* own include */
59 
60 #include "DNA_fluid_types.h"
61 #include "DNA_scene_types.h"
62 
63 #define FLUID_JOB_BAKE_ALL "FLUID_OT_bake_all"
64 #define FLUID_JOB_BAKE_DATA "FLUID_OT_bake_data"
65 #define FLUID_JOB_BAKE_NOISE "FLUID_OT_bake_noise"
66 #define FLUID_JOB_BAKE_MESH "FLUID_OT_bake_mesh"
67 #define FLUID_JOB_BAKE_PARTICLES "FLUID_OT_bake_particles"
68 #define FLUID_JOB_BAKE_GUIDES "FLUID_OT_bake_guides"
69 #define FLUID_JOB_FREE_ALL "FLUID_OT_free_all"
70 #define FLUID_JOB_FREE_DATA "FLUID_OT_free_data"
71 #define FLUID_JOB_FREE_NOISE "FLUID_OT_free_noise"
72 #define FLUID_JOB_FREE_MESH "FLUID_OT_free_mesh"
73 #define FLUID_JOB_FREE_PARTICLES "FLUID_OT_free_particles"
74 #define FLUID_JOB_FREE_GUIDES "FLUID_OT_free_guides"
75 #define FLUID_JOB_BAKE_PAUSE "FLUID_OT_pause_bake"
76 
77 typedef struct FluidJob {
78  /* from wmJob */
79  void *owner;
80  short *stop, *do_update;
81  float *progress;
82  const char *type;
83  const char *name;
84 
85  struct Main *bmain;
89 
91 
92  int success;
93  double start;
94 
97 
98 static inline bool fluid_is_bake_all(FluidJob *job)
99 {
100  return (STREQ(job->type, FLUID_JOB_BAKE_ALL));
101 }
102 static inline bool fluid_is_bake_data(FluidJob *job)
103 {
104  return (STREQ(job->type, FLUID_JOB_BAKE_DATA));
105 }
106 static inline bool fluid_is_bake_noise(FluidJob *job)
107 {
108  return (STREQ(job->type, FLUID_JOB_BAKE_NOISE));
109 }
110 static inline bool fluid_is_bake_mesh(FluidJob *job)
111 {
112  return (STREQ(job->type, FLUID_JOB_BAKE_MESH));
113 }
114 static inline bool fluid_is_bake_particle(FluidJob *job)
115 {
116  return (STREQ(job->type, FLUID_JOB_BAKE_PARTICLES));
117 }
118 static inline bool fluid_is_bake_guiding(FluidJob *job)
119 {
120  return (STREQ(job->type, FLUID_JOB_BAKE_GUIDES));
121 }
122 static inline bool fluid_is_free_all(FluidJob *job)
123 {
124  return (STREQ(job->type, FLUID_JOB_FREE_ALL));
125 }
126 static inline bool fluid_is_free_data(FluidJob *job)
127 {
128  return (STREQ(job->type, FLUID_JOB_FREE_DATA));
129 }
130 static inline bool fluid_is_free_noise(FluidJob *job)
131 {
132  return (STREQ(job->type, FLUID_JOB_FREE_NOISE));
133 }
134 static inline bool fluid_is_free_mesh(FluidJob *job)
135 {
136  return (STREQ(job->type, FLUID_JOB_FREE_MESH));
137 }
138 static inline bool fluid_is_free_particles(FluidJob *job)
139 {
140  return (STREQ(job->type, FLUID_JOB_FREE_PARTICLES));
141 }
142 static inline bool fluid_is_free_guiding(FluidJob *job)
143 {
144  return (STREQ(job->type, FLUID_JOB_FREE_GUIDES));
145 }
146 
147 static bool fluid_initjob(
148  bContext *C, FluidJob *job, wmOperator *op, char *error_msg, int error_size)
149 {
150  FluidModifierData *fmd = NULL;
151  FluidDomainSettings *fds;
153 
155  if (!fmd) {
156  BLI_strncpy(error_msg, N_("Bake failed: no Fluid modifier found"), error_size);
157  return false;
158  }
159  fds = fmd->domain;
160  if (!fds) {
161  BLI_strncpy(error_msg, N_("Bake failed: invalid domain"), error_size);
162  return false;
163  }
164 
165  job->bmain = CTX_data_main(C);
166  job->scene = CTX_data_scene(C);
168  job->ob = ob;
169  job->fmd = fmd;
170  job->type = op->type->idname;
171  job->name = op->type->name;
172 
173  return true;
174 }
175 
176 static bool fluid_validatepaths(FluidJob *job, ReportList *reports)
177 {
178  FluidDomainSettings *fds = job->fmd->domain;
179  char temp_dir[FILE_MAX];
180  temp_dir[0] = '\0';
181  bool is_relative = false;
182 
183  const char *relbase = BKE_modifier_path_relbase(job->bmain, job->ob);
184 
185  /* We do not accept empty paths, they can end in random places silently, see T51176. */
186  if (fds->cache_directory[0] == '\0') {
187  char cache_name[64];
188  BKE_fluid_cache_new_name_for_current_session(sizeof(cache_name), cache_name);
189  BKE_modifier_path_init(fds->cache_directory, sizeof(fds->cache_directory), cache_name);
190  BKE_reportf(reports,
191  RPT_WARNING,
192  "Fluid: Empty cache path, reset to default '%s'",
193  fds->cache_directory);
194  }
195 
196  BLI_strncpy(temp_dir, fds->cache_directory, FILE_MAXDIR);
197  is_relative = BLI_path_abs(temp_dir, relbase);
198 
199  /* Ensure whole path exists */
200  const bool dir_exists = BLI_dir_create_recursive(temp_dir);
201 
202  /* We change path to some presumably valid default value, but do not allow bake process to
203  * continue, this gives user chance to set manually another path. */
204  if (!dir_exists) {
205  char cache_name[64];
206  BKE_fluid_cache_new_name_for_current_session(sizeof(cache_name), cache_name);
207  BKE_modifier_path_init(fds->cache_directory, sizeof(fds->cache_directory), cache_name);
208 
209  BKE_reportf(reports,
210  RPT_ERROR,
211  "Fluid: Could not create cache directory '%s', reset to default '%s'",
212  temp_dir,
213  fds->cache_directory);
214 
215  /* Ensure whole path exists and is writable. */
216  if (!BLI_dir_create_recursive(temp_dir)) {
217  BKE_reportf(reports,
218  RPT_ERROR,
219  "Fluid: Could not use default cache directory '%s', "
220  "please define a valid cache path manually",
221  temp_dir);
222  return false;
223  }
224  /* Copy final dir back into domain settings */
225  BLI_strncpy(fds->cache_directory, temp_dir, FILE_MAXDIR);
226 
227  return false;
228  }
229 
230  /* Change path back to is original state (ie relative or absolute). */
231  if (is_relative) {
232  BLI_path_rel(temp_dir, relbase);
233  }
234 
235  /* Copy final dir back into domain settings */
236  BLI_strncpy(fds->cache_directory, temp_dir, FILE_MAXDIR);
237  return true;
238 }
239 
240 static void fluid_bake_free(void *customdata)
241 {
242  FluidJob *job = customdata;
243  MEM_freeN(job);
244 }
245 
246 static void fluid_bake_sequence(FluidJob *job)
247 {
248  FluidDomainSettings *fds = job->fmd->domain;
249  Scene *scene = job->scene;
250  int frame = 1, orig_frame;
251  int frames;
252  int *pause_frame = NULL;
253  bool is_first_frame;
254 
255  frames = fds->cache_frame_end - fds->cache_frame_start + 1;
256 
257  if (frames <= 0) {
258  BLI_strncpy(fds->error, N_("No frames to bake"), sizeof(fds->error));
259  return;
260  }
261 
262  /* Show progress bar. */
263  if (job->do_update) {
264  *(job->do_update) = true;
265  }
266 
267  /* Get current pause frame (pointer) - depending on bake type. */
268  pause_frame = job->pause_frame;
269 
270  /* Set frame to start point (depending on current pause frame value). */
271  is_first_frame = ((*pause_frame) == 0);
272  frame = is_first_frame ? fds->cache_frame_start : (*pause_frame);
273 
274  /* Save orig frame and update scene frame. */
275  orig_frame = CFRA;
276  CFRA = frame;
277 
278  /* Loop through selected frames. */
279  for (; frame <= fds->cache_frame_end; frame++) {
280  const float progress = (frame - fds->cache_frame_start) / (float)frames;
281 
282  /* Keep track of pause frame - needed to init future loop. */
283  (*pause_frame) = frame;
284 
285  /* If user requested stop, quit baking. */
286  if (G.is_break) {
287  job->success = 0;
288  return;
289  }
290 
291  /* Update progress bar. */
292  if (job->do_update) {
293  *(job->do_update) = true;
294  }
295  if (job->progress) {
296  *(job->progress) = progress;
297  }
298 
299  CFRA = frame;
300 
301  /* Update animation system. */
303 
304  /* If user requested stop, quit baking. */
305  if (G.is_break) {
306  job->success = 0;
307  return;
308  }
309  }
310 
311  /* Restore frame position that we were on before bake. */
312  CFRA = orig_frame;
313 }
314 
315 static void fluid_bake_endjob(void *customdata)
316 {
317  FluidJob *job = customdata;
318  FluidDomainSettings *fds = job->fmd->domain;
319 
320  if (fluid_is_bake_noise(job) || fluid_is_bake_all(job)) {
324  }
325  if (fluid_is_bake_mesh(job) || fluid_is_bake_all(job)) {
329  }
330  if (fluid_is_bake_particle(job) || fluid_is_bake_all(job)) {
334  }
335  if (fluid_is_bake_guiding(job) || fluid_is_bake_all(job)) {
339  }
340  if (fluid_is_bake_data(job) || fluid_is_bake_all(job)) {
344  }
346 
347  G.is_rendering = false;
349  WM_set_locked_interface(G_MAIN->wm.first, false);
350 
351  /* Bake was successful:
352  * Report for ended bake and how long it took. */
353  if (job->success) {
354  /* Show bake info. */
355  WM_reportf(
356  RPT_INFO, "Fluid: %s complete! (%.2f)", job->name, PIL_check_seconds_timer() - job->start);
357  }
358  else {
359  if (fds->error[0] != '\0') {
360  WM_reportf(RPT_ERROR, "Fluid: %s failed: %s", job->name, fds->error);
361  }
362  else { /* User canceled the bake. */
363  WM_reportf(RPT_WARNING, "Fluid: %s canceled!", job->name);
364  }
365  }
366 }
367 
368 static void fluid_bake_startjob(void *customdata, short *stop, short *do_update, float *progress)
369 {
370  FluidJob *job = customdata;
371  FluidDomainSettings *fds = job->fmd->domain;
372 
373  char temp_dir[FILE_MAX];
374  const char *relbase = BKE_modifier_path_relbase_from_global(job->ob);
375 
376  job->stop = stop;
377  job->do_update = do_update;
378  job->progress = progress;
380  job->success = 1;
381 
382  G.is_break = false;
383  G.is_rendering = true;
385 
386  if (fluid_is_bake_noise(job) || fluid_is_bake_all(job)) {
387  BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL);
388  BLI_path_abs(temp_dir, relbase);
389  BLI_dir_create_recursive(temp_dir); /* Create 'noise' subdir if it does not exist already */
393  }
394  if (fluid_is_bake_mesh(job) || fluid_is_bake_all(job)) {
395  BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL);
396  BLI_path_abs(temp_dir, relbase);
397  BLI_dir_create_recursive(temp_dir); /* Create 'mesh' subdir if it does not exist already */
400  job->pause_frame = &fds->cache_frame_pause_mesh;
401  }
402  if (fluid_is_bake_particle(job) || fluid_is_bake_all(job)) {
404  temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL);
405  BLI_path_abs(temp_dir, relbase);
407  temp_dir); /* Create 'particles' subdir if it does not exist already */
411  }
412  if (fluid_is_bake_guiding(job) || fluid_is_bake_all(job)) {
413  BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE, NULL);
414  BLI_path_abs(temp_dir, relbase);
415  BLI_dir_create_recursive(temp_dir); /* Create 'guiding' subdir if it does not exist already */
419  }
420  if (fluid_is_bake_data(job) || fluid_is_bake_all(job)) {
421  BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL);
422  BLI_path_abs(temp_dir, relbase);
423  BLI_dir_create_recursive(temp_dir); /* Create 'config' subdir if it does not exist already */
424 
425  BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL);
426  BLI_path_abs(temp_dir, relbase);
427  BLI_dir_create_recursive(temp_dir); /* Create 'data' subdir if it does not exist already */
430  job->pause_frame = &fds->cache_frame_pause_data;
431 
434  temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL);
435  BLI_path_abs(temp_dir, relbase);
436  BLI_dir_create_recursive(temp_dir); /* Create 'script' subdir if it does not exist already */
437  }
438  }
440 
441  fluid_bake_sequence(job);
442 
443  if (do_update) {
444  *do_update = true;
445  }
446  if (stop) {
447  *stop = 0;
448  }
449 }
450 
451 static void fluid_free_endjob(void *customdata)
452 {
453  FluidJob *job = customdata;
454  FluidDomainSettings *fds = job->fmd->domain;
455 
456  G.is_rendering = false;
458  WM_set_locked_interface(G_MAIN->wm.first, false);
459 
460  /* Reflect the now empty cache in the viewport too. */
462 
463  /* Free was successful:
464  * Report for ended free job and how long it took */
465  if (job->success) {
466  /* Show free job info */
467  WM_reportf(
468  RPT_INFO, "Fluid: %s complete! (%.2f)", job->name, PIL_check_seconds_timer() - job->start);
469  }
470  else {
471  if (fds->error[0] != '\0') {
472  WM_reportf(RPT_ERROR, "Fluid: %s failed: %s", job->name, fds->error);
473  }
474  else { /* User canceled the free job */
475  WM_reportf(RPT_WARNING, "Fluid: %s canceled!", job->name);
476  }
477  }
478 }
479 
480 static void fluid_free_startjob(void *customdata, short *stop, short *do_update, float *progress)
481 {
482  FluidJob *job = customdata;
483  FluidDomainSettings *fds = job->fmd->domain;
484 
485  job->stop = stop;
486  job->do_update = do_update;
487  job->progress = progress;
489  job->success = 1;
490 
491  G.is_break = false;
492  G.is_rendering = true;
494 
495  int cache_map = 0;
496 
497  if (fluid_is_free_data(job) || fluid_is_free_all(job)) {
500  }
501  if (fluid_is_free_noise(job) || fluid_is_free_all(job)) {
502  cache_map |= FLUID_DOMAIN_OUTDATED_NOISE;
503  }
504  if (fluid_is_free_mesh(job) || fluid_is_free_all(job)) {
505  cache_map |= FLUID_DOMAIN_OUTDATED_MESH;
506  }
507  if (fluid_is_free_particles(job) || fluid_is_free_all(job)) {
508  cache_map |= FLUID_DOMAIN_OUTDATED_PARTICLES;
509  }
510  if (fluid_is_free_guiding(job) || fluid_is_free_all(job)) {
514  }
515 #ifdef WITH_FLUID
516  BKE_fluid_cache_free(fds, job->ob, cache_map);
517 #else
518  UNUSED_VARS(fds);
519 #endif
520 
521  *do_update = true;
522  *stop = 0;
523 
524  /* Update scene so that viewport shows freed up scene */
526 }
527 
528 /***************************** Operators ******************************/
529 
530 static int fluid_bake_exec(struct bContext *C, struct wmOperator *op)
531 {
532  FluidJob *job = MEM_mallocN(sizeof(FluidJob), "FluidJob");
533  char error_msg[256] = "\0";
534 
535  if (!fluid_initjob(C, job, op, error_msg, sizeof(error_msg))) {
536  if (error_msg[0]) {
537  BKE_report(op->reports, RPT_ERROR, error_msg);
538  }
539  fluid_bake_free(job);
540  return OPERATOR_CANCELLED;
541  }
542  if (!fluid_validatepaths(job, op->reports)) {
543  fluid_bake_free(job);
544  return OPERATOR_CANCELLED;
545  }
547 
549  fluid_bake_endjob(job);
550  fluid_bake_free(job);
551 
552  return OPERATOR_FINISHED;
553 }
554 
555 static int fluid_bake_invoke(struct bContext *C,
556  struct wmOperator *op,
557  const wmEvent *UNUSED(_event))
558 {
560  FluidJob *job = MEM_mallocN(sizeof(FluidJob), "FluidJob");
561  char error_msg[256] = "\0";
562 
563  if (!fluid_initjob(C, job, op, error_msg, sizeof(error_msg))) {
564  if (error_msg[0]) {
565  BKE_report(op->reports, RPT_ERROR, error_msg);
566  }
567  fluid_bake_free(job);
568  return OPERATOR_CANCELLED;
569  }
570 
571  if (!fluid_validatepaths(job, op->reports)) {
572  fluid_bake_free(job);
573  return OPERATOR_CANCELLED;
574  }
575 
576  /* Clear existing banners so that the upcoming progress bar from this job has more room. */
578 
579  wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
580  CTX_wm_window(C),
581  scene,
582  "Fluid Bake",
585 
589 
591 
592  WM_jobs_start(CTX_wm_manager(C), wm_job);
594 
595  return OPERATOR_RUNNING_MODAL;
596 }
597 
598 static int fluid_bake_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
599 {
600  /* no running blender, remove handler and pass through */
603  }
604 
605  switch (event->type) {
606  case EVT_ESCKEY:
607  return OPERATOR_RUNNING_MODAL;
608  }
609  return OPERATOR_PASS_THROUGH;
610 }
611 
612 static int fluid_free_exec(struct bContext *C, struct wmOperator *op)
613 {
614  FluidModifierData *fmd = NULL;
615  FluidDomainSettings *fds;
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  BKE_report(op->reports, RPT_ERROR, "Bake free failed: pending bake jobs found");
637  return OPERATOR_CANCELLED;
638  }
639 
640  FluidJob *job = MEM_mallocN(sizeof(FluidJob), "FluidJob");
641  job->bmain = CTX_data_main(C);
642  job->scene = scene;
644  job->ob = ob;
645  job->fmd = fmd;
646  job->type = op->type->idname;
647  job->name = op->type->name;
648 
649  if (!fluid_validatepaths(job, op->reports)) {
650  fluid_bake_free(job);
651  return OPERATOR_CANCELLED;
652  }
653 
654  /* Clear existing banners so that the upcoming progress bar from this job has more room. */
656 
657  wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
658  CTX_wm_window(C),
659  scene,
660  "Fluid Free",
663 
667 
669 
670  /* Free Fluid Geometry */
671  WM_jobs_start(CTX_wm_manager(C), wm_job);
672 
673  return OPERATOR_FINISHED;
674 }
675 
676 static int fluid_pause_exec(struct bContext *C, struct wmOperator *op)
677 {
678  FluidModifierData *fmd = NULL;
679  FluidDomainSettings *fds;
681 
682  /*
683  * Get modifier data
684  */
686  if (!fmd) {
687  BKE_report(op->reports, RPT_ERROR, "Bake free failed: no Fluid modifier found");
688  return OPERATOR_CANCELLED;
689  }
690  fds = fmd->domain;
691  if (!fds) {
692  BKE_report(op->reports, RPT_ERROR, "Bake free failed: invalid domain");
693  return OPERATOR_CANCELLED;
694  }
695 
696  G.is_break = true;
697 
698  return OPERATOR_FINISHED;
699 }
700 
702 {
703  /* identifiers */
704  ot->name = "Bake All";
705  ot->description = "Bake Entire Fluid Simulation";
707 
708  /* api callbacks */
713 }
714 
716 {
717  /* identifiers */
718  ot->name = "Free All";
719  ot->description = "Free Entire Fluid Simulation";
721 
722  /* api callbacks */
725 }
726 
728 {
729  /* identifiers */
730  ot->name = "Bake Data";
731  ot->description = "Bake Fluid Data";
733 
734  /* api callbacks */
739 }
740 
742 {
743  /* identifiers */
744  ot->name = "Free Data";
745  ot->description = "Free Fluid Data";
747 
748  /* api callbacks */
751 }
752 
754 {
755  /* identifiers */
756  ot->name = "Bake Noise";
757  ot->description = "Bake Fluid Noise";
759 
760  /* api callbacks */
765 }
766 
768 {
769  /* identifiers */
770  ot->name = "Free Noise";
771  ot->description = "Free Fluid Noise";
773 
774  /* api callbacks */
777 }
778 
780 {
781  /* identifiers */
782  ot->name = "Bake Mesh";
783  ot->description = "Bake Fluid Mesh";
785 
786  /* api callbacks */
791 }
792 
794 {
795  /* identifiers */
796  ot->name = "Free Mesh";
797  ot->description = "Free Fluid Mesh";
799 
800  /* api callbacks */
803 }
804 
806 {
807  /* identifiers */
808  ot->name = "Bake Particles";
809  ot->description = "Bake Fluid Particles";
811 
812  /* api callbacks */
817 }
818 
820 {
821  /* identifiers */
822  ot->name = "Free Particles";
823  ot->description = "Free Fluid Particles";
825 
826  /* api callbacks */
829 }
830 
832 {
833  /* identifiers */
834  ot->name = "Bake Guides";
835  ot->description = "Bake Fluid Guiding";
837 
838  /* api callbacks */
843 }
844 
846 {
847  /* identifiers */
848  ot->name = "Free Guides";
849  ot->description = "Free Fluid Guiding";
851 
852  /* api callbacks */
855 }
856 
858 {
859  /* identifiers */
860  ot->name = "Pause Bake";
861  ot->description = "Pause Bake";
863 
864  /* api callbacks */
867 }
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:689
struct Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Definition: context.c:1401
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
void BKE_fluid_cache_new_name_for_current_session(int maxlen, char *r_name)
Definition: fluid.c:5195
void BKE_fluid_cache_free(struct FluidDomainSettings *fds, struct Object *ob, int cache_map)
#define G_MAIN
Definition: BKE_global.h:232
void BKE_modifier_path_init(char *path, int path_maxlen, const char *name)
const char * BKE_modifier_path_relbase_from_global(struct Object *ob)
const char * BKE_modifier_path_relbase(struct Main *bmain, struct Object *ob)
struct ModifierData * BKE_modifiers_findby_type(const struct Object *ob, ModifierType type)
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
void BKE_reportf(ReportList *reports, ReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_spacedata_draw_locks(bool set)
Definition: screen.c:547
bool BLI_dir_create_recursive(const char *dir) ATTR_NONNULL()
Definition: fileops.c:1329
#define FILE_MAX
size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *path_first,...) ATTR_NONNULL(1
void BLI_path_rel(char *file, const char *relfile) ATTR_NONNULL()
Definition: path_util.c:519
#define FILE_MAXDIR
bool BLI_path_abs(char *path, const char *basepath) ATTR_NONNULL()
Definition: path_util.c:1016
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
#define UNUSED_VARS(...)
#define UNUSED(x)
#define STREQ(a, b)
#define N_(msgid)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:611
@ 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_DATA
#define FLUID_DOMAIN_DIR_PARTICLES
#define FLUID_DOMAIN_DIR_MESH
#define FLUID_DOMAIN_DIR_GUIDE
#define FLUID_DOMAIN_DIR_SCRIPT
@ FLUID_DOMAIN_EXPORT_MANTA_SCRIPT
#define FLUID_DOMAIN_DIR_CONFIG
#define FLUID_DOMAIN_DIR_NOISE
@ eModifierType_Fluid
Object is a sort of wrapper for general info.
#define CFRA
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
struct Object * ED_object_active_context(const struct bContext *C)
bool ED_operator_object_active_editable(struct bContext *C)
Definition: screen_ops.c:366
void ED_update_for_newframe(struct Main *bmain, struct Depsgraph *depsgraph)
Definition: screen_edit.c:1617
Read Guarded memory(de)allocation.
Platform independent time functions.
#define C
Definition: RandGen.cpp:39
@ WM_JOB_TYPE_OBJECT_SIM_FLUID
Definition: WM_api.h:739
@ WM_JOB_PROGRESS
Definition: WM_api.h:726
#define ND_MODIFIER
Definition: WM_types.h:363
#define NC_OBJECT
Definition: WM_types.h:280
Scene scene
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
#define FLUID_JOB_FREE_DATA
Definition: physics_fluid.c:70
static int fluid_bake_invoke(struct bContext *C, struct wmOperator *op, const wmEvent *UNUSED(_event))
#define FLUID_JOB_BAKE_GUIDES
Definition: physics_fluid.c:68
#define FLUID_JOB_BAKE_ALL
Definition: physics_fluid.c:63
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 int fluid_bake_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
static void fluid_bake_startjob(void *customdata, short *stop, short *do_update, float *progress)
static bool fluid_is_bake_noise(FluidJob *job)
static bool fluid_validatepaths(FluidJob *job, ReportList *reports)
#define FLUID_JOB_FREE_MESH
Definition: physics_fluid.c:72
void FLUID_OT_free_particles(wmOperatorType *ot)
static int fluid_pause_exec(struct bContext *C, struct wmOperator *op)
#define FLUID_JOB_FREE_ALL
Definition: physics_fluid.c:69
void FLUID_OT_free_all(wmOperatorType *ot)
void FLUID_OT_bake_guides(wmOperatorType *ot)
static bool fluid_is_free_mesh(FluidJob *job)
void FLUID_OT_free_guides(wmOperatorType *ot)
struct FluidJob FluidJob
#define FLUID_JOB_BAKE_PAUSE
Definition: physics_fluid.c:75
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 int fluid_bake_exec(struct bContext *C, struct wmOperator *op)
static bool fluid_is_bake_all(FluidJob *job)
Definition: physics_fluid.c:98
static void fluid_bake_free(void *customdata)
#define FLUID_JOB_BAKE_NOISE
Definition: physics_fluid.c:65
#define FLUID_JOB_FREE_PARTICLES
Definition: physics_fluid.c:73
void FLUID_OT_bake_all(wmOperatorType *ot)
#define FLUID_JOB_BAKE_PARTICLES
Definition: physics_fluid.c:67
static bool fluid_is_bake_mesh(FluidJob *job)
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
Definition: physics_fluid.c:71
void FLUID_OT_bake_data(wmOperatorType *ot)
static void fluid_free_startjob(void *customdata, short *stop, short *do_update, float *progress)
static int fluid_free_exec(struct bContext *C, struct wmOperator *op)
static bool fluid_is_bake_data(FluidJob *job)
void FLUID_OT_free_noise(wmOperatorType *ot)
#define FLUID_JOB_FREE_GUIDES
Definition: physics_fluid.c:74
#define FLUID_JOB_BAKE_DATA
Definition: physics_fluid.c:64
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
Definition: physics_fluid.c:66
static void fluid_bake_sequence(FluidJob *job)
void FLUID_OT_bake_mesh(wmOperatorType *ot)
char cache_directory[1024]
int * pause_frame
Definition: physics_fluid.c:95
const char * name
Definition: physics_fluid.c:83
short * stop
Definition: physics_fluid.c:80
FluidModifierData * fmd
Definition: physics_fluid.c:90
Object * ob
Definition: physics_fluid.c:88
Depsgraph * depsgraph
Definition: physics_fluid.c:87
const char * type
Definition: physics_fluid.c:82
double start
Definition: physics_fluid.c:93
float * progress
Definition: physics_fluid.c:81
short * do_update
Definition: physics_fluid.c:80
struct Main * bmain
Definition: physics_fluid.c:85
void * owner
Definition: physics_fluid.c:79
Scene * scene
Definition: physics_fluid.c:86
struct FluidDomainSettings * domain
Definition: BKE_main.h:116
short type
Definition: WM_types.h:577
Definition: wm_jobs.c:73
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:768
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
struct ReportList * reports
struct wmOperatorType * type
double PIL_check_seconds_timer(void)
Definition: time.c:80
#define G(x, y, z)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_report_banners_cancel(Main *bmain)
void WM_reportf(ReportType type, const char *format,...)
void WM_set_locked_interface(wmWindowManager *wm, bool lock)
@ EVT_ESCKEY
wmOperatorType * ot
Definition: wm_files.c:3156
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition: wm_jobs.c:450
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, const char *name, int flag, int job_type)
Definition: wm_jobs.c:196
bool WM_jobs_test(wmWindowManager *wm, void *owner, int job_type)
Definition: wm_jobs.c:223
void WM_jobs_callbacks(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *))
Definition: wm_jobs.c:372
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *))
Definition: wm_jobs.c:344
void WM_jobs_timer(wmJob *wm_job, double timestep, unsigned int note, unsigned int endnote)
Definition: wm_jobs.c:360