Blender V4.3
object_bake_simulation.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <fstream>
6#include <iomanip>
7#include <random>
8#include <sstream>
9
10#include "BLI_fileops.hh"
11#include "BLI_path_utils.hh"
12#include "BLI_serialize.hh"
13#include "BLI_string.h"
14#include "BLI_vector.hh"
15
16#include "BLT_translation.hh"
17
18#include "WM_api.hh"
19#include "WM_types.hh"
20
21#include "ED_object.hh"
22#include "ED_screen.hh"
23
24#include "DNA_array_utils.hh"
25#include "DNA_modifier_types.h"
27
30#include "BKE_context.hh"
31#include "BKE_global.hh"
32#include "BKE_lib_id.hh"
33#include "BKE_main.hh"
34#include "BKE_modifier.hh"
35#include "BKE_node_runtime.hh"
36#include "BKE_packedFile.hh"
37#include "BKE_report.hh"
38#include "BKE_scene.hh"
39
40#include "RNA_access.hh"
41#include "RNA_define.hh"
42
43#include "DEG_depsgraph.hh"
44
45#include "MOD_nodes.hh"
46
47#include "object_intern.hh"
48
49#include "WM_api.hh"
50
51#include "UI_interface.hh"
52
53namespace bake = blender::bke::bake;
54
56
58{
60 return false;
61 }
62 return true;
63}
64
74
75static void simulate_to_frame_startjob(void *customdata, wmJobWorkerStatus *worker_status)
76{
77 SimulateToFrameJob &job = *static_cast<SimulateToFrameJob *>(customdata);
78 G.is_rendering = true;
79 G.is_break = false;
80 WM_set_locked_interface(job.wm, true);
81
82 Vector<Object *> objects_to_calc;
83 for (Object *object : job.objects) {
84 if (!BKE_id_is_editable(job.bmain, &object->id)) {
85 continue;
86 }
87 LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
88 if (md->type != eModifierType_Nodes) {
89 continue;
90 }
91 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
92 if (!nmd->runtime->cache) {
93 continue;
94 }
95 for (auto item : nmd->runtime->cache->simulation_cache_by_id.items()) {
96 if (item.value->cache_status != bake::CacheStatus::Baked) {
97 item.value->reset();
98 }
99 }
100 }
101 objects_to_calc.append(object);
102 }
103
104 worker_status->progress = 0.0f;
105 worker_status->do_update = true;
106
107 const float frame_step_size = 1.0f;
108 const float progress_per_frame = 1.0f /
109 (float(job.end_frame - job.start_frame + 1) / frame_step_size);
110 const int old_frame = job.scene->r.cfra;
111
112 for (float frame_f = job.start_frame; frame_f <= job.end_frame; frame_f += frame_step_size) {
113 const SubFrame frame{frame_f};
114
115 if (G.is_break || worker_status->stop) {
116 break;
117 }
118
119 job.scene->r.cfra = frame.frame();
120 job.scene->r.subframe = frame.subframe();
121
123
124 worker_status->progress += progress_per_frame;
125 worker_status->do_update = true;
126 }
127
128 job.scene->r.cfra = old_frame;
130
131 worker_status->progress = 1.0f;
132 worker_status->do_update = true;
133}
134
135static void simulate_to_frame_endjob(void *customdata)
136{
137 SimulateToFrameJob &job = *static_cast<SimulateToFrameJob *>(customdata);
138 WM_set_locked_interface(job.wm, false);
139 G.is_rendering = false;
141}
142
143static int simulate_to_frame_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
144{
146 Scene *scene = CTX_data_scene(C);
148 Main *bmain = CTX_data_main(C);
149
150 SimulateToFrameJob *job = MEM_new<SimulateToFrameJob>(__func__);
151 job->wm = wm;
152 job->bmain = bmain;
153 job->depsgraph = depsgraph;
154 job->scene = scene;
155 job->start_frame = scene->r.sfra;
156 job->end_frame = scene->r.cfra;
157
158 if (RNA_boolean_get(op->ptr, "selected")) {
159 CTX_DATA_BEGIN (C, Object *, object, selected_objects) {
160 job->objects.append(object);
161 }
163 }
164 else {
165 if (Object *object = CTX_data_active_object(C)) {
166 job->objects.append(object);
167 }
168 }
169
170 wmJob *wm_job = WM_jobs_get(wm,
171 CTX_wm_window(C),
173 "Calculate Simulation",
176
178 wm_job, job, [](void *job) { MEM_delete(static_cast<SimulateToFrameJob *>(job)); });
181 wm_job, simulate_to_frame_startjob, nullptr, nullptr, simulate_to_frame_endjob);
182
183 WM_jobs_start(CTX_wm_manager(C), wm_job);
186}
187
196
198{
200 return false;
201 }
203 const bool use_frame_cache = ob->flag & OB_FLAG_USE_SIMULATION_CACHE;
204 if (!use_frame_cache) {
205 CTX_wm_operator_poll_msg_set(C, "Cache has to be enabled");
206 return false;
207 }
208 return true;
209}
210
216
218 std::optional<bake::BakePath> path;
221 std::unique_ptr<bake::BlobWriteSharing> blob_sharing;
222};
223
231
233{
234 for (NodeBakeRequest &request : job.bake_requests) {
235 request.nmd->runtime->cache->requested_bakes.add(request.bake_id);
236 /* Using #DEG_id_tag_update would tag this as user-modified which is not the case here and has
237 * the issue that it invalidates simulation caches. */
239 job.depsgraph, &request.object->id, ID_RECALC_GEOMETRY);
240 }
241}
242
244{
245 for (NodeBakeRequest &request : job.bake_requests) {
246 request.nmd->runtime->cache->requested_bakes.clear();
247 }
248}
249
250static void bake_geometry_nodes_startjob(void *customdata, wmJobWorkerStatus *worker_status)
251{
252 BakeGeometryNodesJob &job = *static_cast<BakeGeometryNodesJob *>(customdata);
253 G.is_rendering = true;
254 G.is_break = false;
255
256 int global_bake_start_frame = INT32_MAX;
257 int global_bake_end_frame = INT32_MIN;
258
259 for (NodeBakeRequest &request : job.bake_requests) {
260 global_bake_start_frame = std::min(global_bake_start_frame, request.frame_start);
261 global_bake_end_frame = std::max(global_bake_end_frame, request.frame_end);
262 }
263
264 worker_status->progress = 0.0f;
265 worker_status->do_update = true;
266
267 const int frames_to_bake = global_bake_end_frame - global_bake_start_frame + 1;
268
269 const float frame_step_size = 1.0f;
270 const float progress_per_frame = frame_step_size / frames_to_bake;
271 const int old_frame = job.scene->r.cfra;
272
273 struct MemoryBakeFile {
274 std::string name;
275 std::string data;
276 };
277
278 struct PackedBake {
279 Vector<MemoryBakeFile> meta_files;
280 Vector<MemoryBakeFile> blob_files;
281 };
282
283 Map<NodeBakeRequest *, PackedBake> packed_data_by_bake;
285
286 for (float frame_f = global_bake_start_frame; frame_f <= global_bake_end_frame;
287 frame_f += frame_step_size)
288 {
289 const SubFrame frame{frame_f};
290
291 if (G.is_break || worker_status->stop) {
292 break;
293 }
294
295 job.scene->r.cfra = frame.frame();
296 job.scene->r.subframe = frame.subframe();
297
299
301
303
304 const std::string frame_file_name = bake::frame_to_file_name(frame);
305
306 for (NodeBakeRequest &request : job.bake_requests) {
307 NodesModifierData &nmd = *request.nmd;
308 bake::ModifierCache &modifier_cache = *nmd.runtime->cache;
309 const bake::NodeBakeCache *bake_cache = modifier_cache.get_node_bake_cache(request.bake_id);
310 if (bake_cache == nullptr) {
311 continue;
312 }
313 if (bake_cache->frames.is_empty()) {
314 continue;
315 }
316 const bake::FrameCache &frame_cache = *bake_cache->frames.last();
317 if (frame_cache.frame != frame) {
318 continue;
319 }
320
321 int64_t &written_size = size_by_bake.lookup_or_add(&request, 0);
322
323 if (request.path.has_value()) {
324 char meta_path[FILE_MAX];
325 BLI_path_join(meta_path,
326 sizeof(meta_path),
327 request.path->meta_dir.c_str(),
328 (frame_file_name + ".json").c_str());
330 bake::DiskBlobWriter blob_writer{request.path->blobs_dir, frame_file_name};
331 fstream meta_file{meta_path, std::ios::out};
332 bake::serialize_bake(frame_cache.state, blob_writer, *request.blob_sharing, meta_file);
333 written_size += blob_writer.written_size();
334 written_size += meta_file.tellp();
335 }
336 else {
337 PackedBake &packed_data = packed_data_by_bake.lookup_or_add_default(&request);
338
339 bake::MemoryBlobWriter blob_writer{frame_file_name};
340 std::ostringstream meta_file{std::ios::binary};
341 bake::serialize_bake(frame_cache.state, blob_writer, *request.blob_sharing, meta_file);
342
343 packed_data.meta_files.append({frame_file_name + ".json", meta_file.str()});
345 blob_writer.get_stream_by_name();
346 for (auto &&item : blob_stream_by_name.items()) {
347 std::string data = item.value.stream->str();
348 if (data.empty()) {
349 continue;
350 }
351 packed_data.blob_files.append({item.key, std::move(data)});
352 }
353 written_size += blob_writer.written_size();
354 written_size += meta_file.tellp();
355 }
356 }
357
358 worker_status->progress += progress_per_frame;
359 worker_status->do_update = true;
360 }
361
362 /* Update bake sizes. */
363 for (NodeBakeRequest &request : job.bake_requests) {
364 NodesModifierBake *bake = request.nmd->find_bake(request.bake_id);
365 bake->bake_size = size_by_bake.lookup_default(&request, 0);
366 }
367
368 /* Store gathered data as packed data. */
369 for (NodeBakeRequest &request : job.bake_requests) {
370 NodesModifierBake *bake = request.nmd->find_bake(request.bake_id);
371
372 PackedBake *packed_data = packed_data_by_bake.lookup_ptr(&request);
373 if (!packed_data) {
374 continue;
375 }
376
377 NodesModifierPackedBake *packed_bake = MEM_cnew<NodesModifierPackedBake>(__func__);
378
379 packed_bake->meta_files_num = packed_data->meta_files.size();
380 packed_bake->blob_files_num = packed_data->blob_files.size();
381
382 packed_bake->meta_files = MEM_cnew_array<NodesModifierBakeFile>(packed_bake->meta_files_num,
383 __func__);
384 packed_bake->blob_files = MEM_cnew_array<NodesModifierBakeFile>(packed_bake->blob_files_num,
385 __func__);
386
387 auto transfer_to_bake =
388 [&](NodesModifierBakeFile *bake_files, MemoryBakeFile *memory_bake_files, const int num) {
389 for (const int i : IndexRange(num)) {
390 NodesModifierBakeFile &bake_file = bake_files[i];
391 MemoryBakeFile &memory = memory_bake_files[i];
392 bake_file.name = BLI_strdup_null(memory.name.c_str());
393 const int64_t data_size = memory.data.size();
394 if (data_size == 0) {
395 continue;
396 }
397 const auto *sharing_info = new blender::ImplicitSharedValue<std::string>(
398 std::move(memory.data));
399 const void *data = sharing_info->data.data();
400 bake_file.packed_file = BKE_packedfile_new_from_memory(data, data_size, sharing_info);
401 }
402 };
403
404 transfer_to_bake(
405 packed_bake->meta_files, packed_data->meta_files.data(), packed_bake->meta_files_num);
406 transfer_to_bake(
407 packed_bake->blob_files, packed_data->blob_files.data(), packed_bake->blob_files_num);
408
409 /* Should have been freed before. */
410 BLI_assert(bake->packed == nullptr);
411 bake->packed = packed_bake;
412 }
413
414 /* Tag simulations as being baked. */
415 for (NodeBakeRequest &request : job.bake_requests) {
416 if (request.node_type != GEO_NODE_SIMULATION_OUTPUT) {
417 continue;
418 }
419 NodesModifierData &nmd = *request.nmd;
420 if (bake::SimulationNodeCache *node_cache = nmd.runtime->cache->get_simulation_node_cache(
421 request.bake_id))
422 {
423 if (!node_cache->bake.frames.is_empty()) {
424 /* Tag the caches as being baked so that they are not changed anymore. */
425 node_cache->cache_status = bake::CacheStatus::Baked;
426 }
427 }
428 DEG_id_tag_update(&request.object->id, ID_RECALC_GEOMETRY);
429 }
430
431 job.scene->r.cfra = old_frame;
433
434 worker_status->progress = 1.0f;
435 worker_status->do_update = true;
436}
437
438static void bake_geometry_nodes_endjob(void *customdata)
439{
440 BakeGeometryNodesJob &job = *static_cast<BakeGeometryNodesJob *>(customdata);
441 WM_set_locked_interface(job.wm, false);
442 G.is_rendering = false;
446}
447
449{
451 &bake.data_blocks_num,
452 &bake.active_data_block,
453 [](NodesModifierDataBlock *data_block) {
454 nodes_modifier_data_block_destruct(data_block, true);
455 });
456}
457
459{
460 switch (request.node_type) {
462 if (bake::SimulationNodeCache *node_cache =
463 request.nmd->runtime->cache->get_simulation_node_cache(request.bake_id))
464 {
465 node_cache->reset();
466 }
467 break;
468 }
469 case GEO_NODE_BAKE: {
470 if (bake::BakeNodeCache *node_cache = request.nmd->runtime->cache->get_bake_node_cache(
471 request.bake_id))
472 {
473 node_cache->reset();
474 }
475 break;
476 }
477 }
478}
479
480static void try_delete_bake(
481 bContext *C, Object &object, NodesModifierData &nmd, const int bake_id, ReportList *reports)
482{
483 Main *bmain = CTX_data_main(C);
484 if (!nmd.runtime->cache) {
485 return;
486 }
487 bake::ModifierCache &modifier_cache = *nmd.runtime->cache;
488 std::lock_guard lock{modifier_cache.mutex};
489 if (auto *node_cache = modifier_cache.simulation_cache_by_id.lookup_ptr(bake_id)) {
490 (*node_cache)->reset();
491 }
492 else if (auto *node_cache = modifier_cache.bake_cache_by_id.lookup_ptr(bake_id)) {
493 (*node_cache)->reset();
494 }
495 NodesModifierBake *bake = nmd.find_bake(bake_id);
496 if (!bake) {
497 return;
498 }
500
501 if (bake->packed) {
503 bake->packed = nullptr;
504 }
505
506 const std::optional<bake::BakePath> bake_path = bake::get_node_bake_path(
507 *bmain, object, nmd, bake_id);
508 if (!bake_path) {
509 return;
510 }
511 const char *meta_dir = bake_path->meta_dir.c_str();
512 if (BLI_exists(meta_dir)) {
513 if (BLI_delete(meta_dir, true, true)) {
514 BKE_reportf(reports, RPT_ERROR, "Failed to remove metadata directory %s", meta_dir);
515 }
516 }
517 const char *blobs_dir = bake_path->blobs_dir.c_str();
518 if (BLI_exists(blobs_dir)) {
519 if (BLI_delete(blobs_dir, true, true)) {
520 BKE_reportf(reports, RPT_ERROR, "Failed to remove blobs directory %s", blobs_dir);
521 }
522 }
523 if (bake_path->bake_dir.has_value()) {
524 const char *zone_bake_dir = bake_path->bake_dir->c_str();
525 /* Try to delete zone bake directory if it is empty. */
526 BLI_delete(zone_bake_dir, true, false);
527 }
528 if (const std::optional<std::string> modifier_bake_dir = bake::get_modifier_bake_path(
529 *bmain, object, nmd))
530 {
531 /* Try to delete modifier bake directory if it is empty. */
532 BLI_delete(modifier_bake_dir->c_str(), true, false);
533 }
534}
535
540 Sync,
544 Async
545};
546
549 wmOperator *op,
550 const BakeRequestsMode mode)
551{
552 for (NodeBakeRequest &request : requests) {
553 reset_old_bake_cache(request);
554 if (NodesModifierBake *bake = request.nmd->find_bake(request.bake_id)) {
556 }
557 try_delete_bake(C, *request.object, *request.nmd, request.bake_id, op->reports);
558 }
559
560 BakeGeometryNodesJob *job = MEM_new<BakeGeometryNodesJob>(__func__);
561 job->wm = CTX_wm_manager(C);
562 job->bmain = CTX_data_main(C);
564 job->scene = CTX_data_scene(C);
565 job->bake_requests = std::move(requests);
566 WM_set_locked_interface(job->wm, true);
567
568 if (mode == BakeRequestsMode::Sync) {
569 wmJobWorkerStatus worker_status{};
570 bake_geometry_nodes_startjob(job, &worker_status);
572 MEM_delete(job);
573 return OPERATOR_FINISHED;
574 }
575
576 wmJob *wm_job = WM_jobs_get(job->wm,
577 CTX_wm_window(C),
578 job->scene,
579 "Bake Nodes",
582
584 wm_job, job, [](void *job) { MEM_delete(static_cast<BakeGeometryNodesJob *>(job)); });
588
589 WM_jobs_start(CTX_wm_manager(C), wm_job);
592}
593
595 Scene &scene,
596 const Span<Object *> objects)
597{
599 for (Object *object : objects) {
600 if (!BKE_id_is_editable(&bmain, &object->id)) {
601 continue;
602 }
603 LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
604 if (md->type != eModifierType_Nodes) {
605 continue;
606 }
608 continue;
609 }
610 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
611 if (!nmd->node_group) {
612 continue;
613 }
614 if (!nmd->runtime->cache) {
615 continue;
616 }
617 for (const bNestedNodeRef &nested_node_ref : nmd->node_group->nested_node_refs_span()) {
618 const int id = nested_node_ref.id;
619 const bNode *node = nmd->node_group->find_nested_node(id);
620 if (node->type != GEO_NODE_SIMULATION_OUTPUT) {
621 continue;
622 }
623 NodeBakeRequest request;
624 request.object = object;
625 request.nmd = nmd;
626 request.bake_id = id;
627 request.node_type = node->type;
628 request.blob_sharing = std::make_unique<bake::BlobWriteSharing>();
630 request.path = bake::get_node_bake_path(bmain, *object, *nmd, id);
631 }
632 std::optional<IndexRange> frame_range = bake::get_node_bake_frame_range(
633 scene, *object, *nmd, id);
634 if (!frame_range) {
635 continue;
636 }
637 request.frame_start = frame_range->first();
638 request.frame_end = frame_range->last();
639
640 requests.append(std::move(request));
641 }
642 }
643 }
644 return requests;
645}
646
648{
649 Scene *scene = CTX_data_scene(C);
650 Main *bmain = CTX_data_main(C);
651
652 Vector<Object *> objects;
653 if (RNA_boolean_get(op->ptr, "selected")) {
654 CTX_DATA_BEGIN (C, Object *, object, selected_objects) {
655 objects.append(object);
656 }
658 }
659 else {
660 if (Object *object = CTX_data_active_object(C)) {
661 objects.append(object);
662 }
663 }
664
665 return collect_simulations_to_bake(*bmain, *scene, objects);
666}
667
669{
671 return start_bake_job(C, std::move(requests), op, BakeRequestsMode::Sync);
672}
673
676 {
677 /* Normalize the paths so we can compare them. */
678 DynamicStackBuffer<256> norm_buf(s.size() + 1, 8);
679 memcpy(norm_buf.buffer(), s.data(), s.size() + 1);
680 char *norm = static_cast<char *>(norm_buf.buffer());
681
683
684 /* Strip ending slash. */
686
688 return get_default_hash(norm);
689 }
690};
691
693 bool operator()(const StringRef a, const StringRef b) const
694 {
695 return BLI_path_cmp_normalized(a.data(), b.data()) == 0;
696 }
697};
698
699static bool bake_directory_has_data(const StringRefNull absolute_bake_dir)
700{
701 char meta_dir[FILE_MAX];
702 BLI_path_join(meta_dir, sizeof(meta_dir), absolute_bake_dir.c_str(), "meta");
703 char blobs_dir[FILE_MAX];
704 BLI_path_join(blobs_dir, sizeof(blobs_dir), absolute_bake_dir.c_str(), "blobs");
705
706 if (!BLI_is_dir(meta_dir) || !BLI_is_dir(blobs_dir)) {
707 return false;
708 }
709
710 return true;
711}
712
714{
716 return true;
717 }
718 for (const NodesModifierBake &bake : Span{nmd.bakes, nmd.bakes_num}) {
719 if (bake.bake_target == NODES_MODIFIER_BAKE_TARGET_DISK) {
720 return true;
721 }
722 }
723 return false;
724}
725
727 Object &object,
729 wmOperator *op)
730{
731 const bool bake_directory_set = !StringRef(nmd.bake_directory).is_empty();
732 if (bake_directory_set) {
733 return;
734 }
735 if (!may_have_disk_bake(nmd)) {
736 return;
737 }
738
739 Main *bmain = CTX_data_main(C);
740
742 RPT_INFO,
743 "Bake directory of object %s, modifier %s is empty, setting default path",
744 object.id.name + 2,
745 nmd.modifier.name);
746
748 bake::get_default_modifier_bake_directory(*bmain, object, nmd).c_str());
749}
750
752 wmOperator *op,
753 const Span<Object *> objects)
754{
755 Main *bmain = CTX_data_main(C);
756
757 for (Object *object : objects) {
758 if (!BKE_id_is_editable(bmain, &object->id)) {
759 continue;
760 }
761
762 LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
763 if (md->type != eModifierType_Nodes) {
764 continue;
765 }
766 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
768 }
769 }
770}
771
772/* Map for counting path references. */
773using PathUsersMap = Map<std::string,
774 int,
775 default_inline_buffer_capacity(sizeof(std::string)),
779
781{
782 Main *bmain = CTX_data_main(C);
783
784 PathUsersMap path_users;
785 for (const Object *object : objects) {
786 const char *base_path = ID_BLEND_PATH(bmain, &object->id);
787
788 LISTBASE_FOREACH (const ModifierData *, md, &object->modifiers) {
789 if (md->type != eModifierType_Nodes) {
790 continue;
791 }
792 const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
793 if (StringRef(nmd->bake_directory).is_empty()) {
794 continue;
795 }
796
797 char absolute_bake_dir[FILE_MAX];
798 STRNCPY(absolute_bake_dir, nmd->bake_directory);
799 BLI_path_abs(absolute_bake_dir, base_path);
800 path_users.add_or_modify(
801 absolute_bake_dir, [](int *value) { *value = 1; }, [](int *value) { ++(*value); });
802 }
803 }
804
805 return path_users;
806}
807
808static int bake_simulation_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
809{
810 Vector<Object *> objects;
811 if (RNA_boolean_get(op->ptr, "selected")) {
812 CTX_DATA_BEGIN (C, Object *, object, selected_objects) {
813 objects.append(object);
814 }
816 }
817 else {
818 if (Object *object = CTX_data_active_object(C)) {
819 objects.append(object);
820 }
821 }
822
823 /* Set empty paths to default if necessary. */
824 bake_simulation_validate_paths(C, op, objects);
825
826 PathUsersMap path_users = bake_simulation_get_path_users(C, objects);
827 bool has_path_conflict = false;
828 bool has_existing_bake_data = false;
829 for (const auto &item : path_users.items()) {
830 /* Check if multiple caches are writing to the same bake directory. */
831 if (item.value > 1) {
833 RPT_ERROR,
834 "Path conflict: %d caches set to path %s",
835 item.value,
836 item.key.data());
837 has_path_conflict = true;
838 }
839
840 /* Check if path exists and contains bake data already. */
841 if (bake_directory_has_data(item.key.data())) {
842 has_existing_bake_data = true;
843 }
844 }
845
846 if (has_path_conflict) {
848 return OPERATOR_CANCELLED;
849 }
850 if (has_existing_bake_data) {
851 return WM_operator_confirm_ex(C,
852 op,
853 IFACE_("Overwrite existing bake data?"),
854 nullptr,
855 IFACE_("Bake"),
857 false);
858 }
860 return start_bake_job(C, std::move(requests), op, BakeRequestsMode::Async);
861}
862
870
872{
873 Vector<Object *> objects;
874 if (RNA_boolean_get(op->ptr, "selected")) {
875 CTX_DATA_BEGIN (C, Object *, object, selected_objects) {
876 objects.append(object);
877 }
879 }
880 else {
881 if (Object *object = CTX_data_active_object(C)) {
882 objects.append(object);
883 }
884 }
885
886 if (objects.is_empty()) {
887 return OPERATOR_CANCELLED;
888 }
889
890 for (Object *object : objects) {
891 LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
892 if (md->type == eModifierType_Nodes) {
893 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
894 for (const NodesModifierBake &bake : Span(nmd->bakes, nmd->bakes_num)) {
895 try_delete_bake(C, *object, *nmd, bake.id, op->reports);
896 }
897 }
898 }
899
901 }
902
904
905 return OPERATOR_FINISHED;
906}
907
909{
910 Main *bmain = CTX_data_main(C);
911 Scene *scene = CTX_data_scene(C);
912 Object *object = reinterpret_cast<Object *>(
914 if (object == nullptr) {
915 return {};
916 }
917 char *modifier_name = RNA_string_get_alloc(op->ptr, "modifier_name", nullptr, 0, nullptr);
918 if (modifier_name == nullptr) {
919 return {};
920 }
922
924 if (md == nullptr) {
925 return {};
926 }
927 NodesModifierData &nmd = *reinterpret_cast<NodesModifierData *>(md);
928 if (nmd.node_group == nullptr) {
929 return {};
930 }
932 BKE_report(op->reports, RPT_ERROR, "Modifier containing the node is disabled");
933 return {};
934 }
935
937
938 const int bake_id = RNA_int_get(op->ptr, "bake_id");
939 const bNode *node = nmd.node_group->find_nested_node(bake_id);
940 if (node == nullptr) {
941 return {};
942 }
943 if (!ELEM(node->type, GEO_NODE_SIMULATION_OUTPUT, GEO_NODE_BAKE)) {
944 return {};
945 }
946
947 NodeBakeRequest request;
948 request.object = object;
949 request.nmd = &nmd;
950 request.bake_id = bake_id;
951 request.node_type = node->type;
952 request.blob_sharing = std::make_unique<bake::BlobWriteSharing>();
953
954 const NodesModifierBake *bake = nmd.find_bake(bake_id);
955 if (!bake) {
956 return {};
957 }
958 if (bake::get_node_bake_target(*object, nmd, bake_id) == NODES_MODIFIER_BAKE_TARGET_DISK) {
959 request.path = bake::get_node_bake_path(*bmain, *object, nmd, bake_id);
960 if (!request.path) {
962 RPT_INFO,
963 "Can't determine bake location on disk. Falling back to packed bake.");
964 }
965 }
966
967 if (node->type == GEO_NODE_BAKE && bake->bake_mode == NODES_MODIFIER_BAKE_MODE_STILL) {
968 const int current_frame = scene->r.cfra;
969 request.frame_start = current_frame;
970 request.frame_end = current_frame;
971 /* Delete old bake because otherwise this wouldn't be a still frame bake. This is not done for
972 * other bakes to avoid loosing data when starting a bake. */
973 try_delete_bake(C, *object, nmd, bake_id, op->reports);
974 }
975 else {
976 const std::optional<IndexRange> frame_range = bake::get_node_bake_frame_range(
977 *scene, *object, nmd, bake_id);
978 if (!frame_range.has_value()) {
979 return {};
980 }
981 if (frame_range->is_empty()) {
982 return {};
983 }
984 request.frame_start = frame_range->first();
985 request.frame_end = frame_range->last();
986 }
987
989 requests.append(std::move(request));
990 return requests;
991}
992
993static int bake_single_node_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
994{
996 if (requests.is_empty()) {
997 return OPERATOR_CANCELLED;
998 }
999 return start_bake_job(C, std::move(requests), op, BakeRequestsMode::Async);
1000}
1001
1003{
1005 if (requests.is_empty()) {
1006 return OPERATOR_CANCELLED;
1007 }
1008 return start_bake_job(C, std::move(requests), op, BakeRequestsMode::Sync);
1009}
1010
1011static int bake_single_node_modal(bContext *C, wmOperator * /*op*/, const wmEvent * /*event*/)
1012{
1015 }
1016 return OPERATOR_PASS_THROUGH;
1017}
1018
1020{
1021 Main *bmain = CTX_data_main(C);
1022 Object *object = reinterpret_cast<Object *>(
1024 if (object == nullptr) {
1025 return OPERATOR_CANCELLED;
1026 }
1027 char *modifier_name = RNA_string_get_alloc(op->ptr, "modifier_name", nullptr, 0, nullptr);
1028 if (modifier_name == nullptr) {
1029 return OPERATOR_CANCELLED;
1030 }
1032
1034 if (md == nullptr) {
1035 return OPERATOR_CANCELLED;
1036 }
1037 NodesModifierData &nmd = *reinterpret_cast<NodesModifierData *>(md);
1038 const int bake_id = RNA_int_get(op->ptr, "bake_id");
1039
1040 try_delete_bake(C, *object, nmd, bake_id, op->reports);
1041
1044 WM_main_add_notifier(NC_NODE, nullptr);
1045 return OPERATOR_FINISHED;
1046}
1047
1049{
1050 Main *bmain = CTX_data_main(C);
1051 Object *object = reinterpret_cast<Object *>(
1053 if (object == nullptr) {
1054 return OPERATOR_CANCELLED;
1055 }
1056 char *modifier_name = RNA_string_get_alloc(op->ptr, "modifier_name", nullptr, 0, nullptr);
1057 if (modifier_name == nullptr) {
1058 return OPERATOR_CANCELLED;
1059 }
1061
1063 if (md == nullptr) {
1064 return OPERATOR_CANCELLED;
1065 }
1066 NodesModifierData &nmd = *reinterpret_cast<NodesModifierData *>(md);
1067 const int bake_id = RNA_int_get(op->ptr, "bake_id");
1068
1069 const std::optional<bake::BakePath> bake_path = bake::get_node_bake_path(
1070 *bmain, *object, nmd, bake_id);
1071 if (!bake_path) {
1072 return OPERATOR_CANCELLED;
1073 }
1074 NodesModifierBake *bake = nmd.find_bake(bake_id);
1075 if (!bake) {
1076 return OPERATOR_CANCELLED;
1077 }
1078
1079 bake::pack_geometry_nodes_bake(*bmain, op->reports, *object, nmd, *bake);
1080
1082 WM_main_add_notifier(NC_NODE, nullptr);
1083 return OPERATOR_FINISHED;
1084}
1085
1086static int unpack_single_bake_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
1087{
1088 uiPopupMenu *pup;
1089 uiLayout *layout;
1090
1091 pup = UI_popup_menu_begin(C, IFACE_("Unpack"), ICON_NONE);
1092 layout = UI_popup_menu_layout(pup);
1093
1095 uiItemsFullEnumO(layout,
1096 op->type->idname,
1097 "method",
1098 static_cast<IDProperty *>(op->ptr->data),
1100 UI_ITEM_NONE);
1101
1102 UI_popup_menu_end(C, pup);
1103
1104 return OPERATOR_INTERFACE;
1105}
1106
1108{
1109 Main *bmain = CTX_data_main(C);
1110 Object *object = reinterpret_cast<Object *>(
1112 if (object == nullptr) {
1113 return OPERATOR_CANCELLED;
1114 }
1115 char *modifier_name = RNA_string_get_alloc(op->ptr, "modifier_name", nullptr, 0, nullptr);
1116 if (modifier_name == nullptr) {
1117 return OPERATOR_CANCELLED;
1118 }
1120
1122 if (md == nullptr) {
1123 return OPERATOR_CANCELLED;
1124 }
1125 NodesModifierData &nmd = *reinterpret_cast<NodesModifierData *>(md);
1126 const int bake_id = RNA_int_get(op->ptr, "bake_id");
1127 NodesModifierBake *bake = nmd.find_bake(bake_id);
1128 if (!bake) {
1129 return OPERATOR_CANCELLED;
1130 }
1131
1132 const ePF_FileStatus method = ePF_FileStatus(RNA_enum_get(op->ptr, "method"));
1133
1135 *bmain, op->reports, *object, nmd, *bake, method);
1136 if (result != bake::UnpackGeometryNodesBakeResult::Success) {
1137 return OPERATOR_CANCELLED;
1138 }
1139
1141 WM_main_add_notifier(NC_NODE, nullptr);
1142 return OPERATOR_FINISHED;
1143}
1144
1146{
1147 ot->name = "Calculate Simulation to Frame";
1148 ot->description =
1149 "Calculate simulations in geometry nodes modifiers from the start to current frame";
1150 ot->idname = __func__;
1151
1155
1157 "selected",
1158 false,
1159 "Selected",
1160 "Calculate all selected objects instead of just the active object");
1161}
1162
1164{
1165 ot->name = "Bake Simulation";
1166 ot->description = "Bake simulations in geometry nodes modifiers";
1167 ot->idname = __func__;
1168
1173
1174 RNA_def_boolean(ot->srna, "selected", false, "Selected", "Bake cache on all selected objects");
1175}
1176
1178{
1179 ot->name = "Delete Cached Simulation";
1180 ot->description = "Delete cached/baked simulations in geometry nodes modifiers";
1181 ot->idname = __func__;
1182
1185
1186 RNA_def_boolean(ot->srna, "selected", false, "Selected", "Delete cache on all selected objects");
1187}
1188
1190{
1192
1194 "modifier_name",
1195 nullptr,
1196 0,
1197 "Modifier Name",
1198 "Name of the modifier that contains the node");
1200 ot->srna, "bake_id", 0, 0, INT32_MAX, "Bake ID", "Nested node id of the node", 0, INT32_MAX);
1201}
1202
1204{
1205 ot->name = "Bake Geometry Node";
1206 ot->description = "Bake a single bake node or simulation";
1207 ot->idname = "OBJECT_OT_geometry_node_bake_single";
1208
1212
1214}
1215
1217{
1218 ot->name = "Delete Geometry Node Bake";
1219 ot->description = "Delete baked data of a single bake node or simulation";
1220 ot->idname = "OBJECT_OT_geometry_node_bake_delete_single";
1221
1223
1225}
1226
1228{
1229 ot->name = "Pack Geometry Node Bake";
1230 ot->description = "Pack baked data from disk into the .blend file";
1231 ot->idname = "OBJECT_OT_geometry_node_bake_pack_single";
1232
1234
1236}
1237
1239{
1240 ot->name = "Unpack Geometry Node Bake";
1241 ot->description = "Unpack baked data from the .blend file to disk";
1242 ot->idname = "OBJECT_OT_geometry_node_bake_unpack_single";
1243
1246
1248
1249 static const EnumPropertyItem method_items[] = {
1250 {PF_USE_LOCAL,
1251 "USE_LOCAL",
1252 0,
1253 "Use bake from current directory (create when necessary)",
1254 ""},
1256 "WRITE_LOCAL",
1257 0,
1258 "Write bake to current directory (overwrite existing bake)",
1259 ""},
1261 "USE_ORIGINAL",
1262 0,
1263 "Use bake in original location (create when necessary)",
1264 ""},
1266 "WRITE_ORIGINAL",
1267 0,
1268 "Write bake to original location (overwrite existing file)",
1269 ""},
1270 {0, nullptr, 0, nullptr, nullptr},
1271 };
1272
1273 RNA_def_enum(ot->srna, "method", method_items, PF_USE_LOCAL, "Method", "How to unpack");
1274}
1275
1276} // namespace blender::ed::object::bake_simulation
#define CTX_DATA_BEGIN(C, Type, instance, member)
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
wmWindow * CTX_wm_window(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
#define CTX_DATA_END
bool BKE_id_is_editable(const Main *bmain, const ID *id)
Definition lib_id.cc:2456
bool BKE_modifier_is_enabled(const Scene *scene, ModifierData *md, int required_mode)
ModifierData * BKE_modifiers_findby_name(const Object *ob, const char *name)
#define GEO_NODE_SIMULATION_OUTPUT
Definition BKE_node.hh:1331
#define GEO_NODE_BAKE
Definition BKE_node.hh:1350
PackedFile * BKE_packedfile_new_from_memory(const void *mem, int memlen, const blender::ImplicitSharingInfo *sharing_info=nullptr)
ePF_FileStatus
@ PF_USE_ORIGINAL
@ PF_USE_LOCAL
@ PF_WRITE_ORIGINAL
@ PF_WRITE_LOCAL
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:125
void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph)
Definition scene.cc:2647
#define BLI_assert(a)
Definition BLI_assert.h:50
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:350
int BLI_delete(const char *path, bool dir, bool recursive) ATTR_NONNULL()
bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:433
bool BLI_file_ensure_parent_dir_exists(const char *filepath) ATTR_NONNULL(1)
Definition fileops_c.cc:429
File and directory operations.
#define LISTBASE_FOREACH(type, var, list)
#define BLI_SCOPED_DEFER(function_to_defer)
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
#define FILE_MAX
void BLI_path_slash_native(char *path) ATTR_NONNULL(1)
int BLI_path_normalize(char *path) ATTR_NONNULL(1)
#define BLI_path_join(...)
int BLI_path_cmp_normalized(const char *p1, const char *p2) ATTR_NONNULL(1
void BLI_path_slash_rstrip(char *path) ATTR_NONNULL(1)
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.c:40
#define STRNCPY(dst, src)
Definition BLI_string.h:593
char * BLI_strdup_null(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_MALLOC
Definition string.c:45
#define ELEM(...)
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_id_tag_update_for_side_effect_request(Depsgraph *depsgraph, ID *id, unsigned int flags)
void DEG_time_tag_update(Main *bmain)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
#define ID_BLEND_PATH(_bmain, _id)
Definition DNA_ID.h:647
@ ID_OB
@ NODES_MODIFIER_BAKE_TARGET_DISK
@ eModifierMode_Realtime
@ eModifierType_Nodes
@ NODES_MODIFIER_BAKE_MODE_STILL
@ OB_FLAG_USE_SIMULATION_CACHE
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
bool ED_operator_object_active(bContext *C)
#define MEM_SAFE_FREE(v)
void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname, IDProperty *properties, wmOperatorCallContext context, eUI_Item_Flag flag, const int active=-1)
void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
#define UI_ITEM_NONE
uiPopupMenu * UI_popup_menu_begin(bContext *C, const char *title, int icon) ATTR_NONNULL()
uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
void UI_popup_menu_reports(bContext *C, ReportList *reports) ATTR_NONNULL()
void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext)
@ ALERT_ICON_NONE
@ WM_JOB_TYPE_CALCULATE_SIMULATION_NODES
Definition WM_api.hh:1609
@ WM_JOB_TYPE_BAKE_GEOMETRY_NODES
Definition WM_api.hh:1610
@ WM_JOB_PROGRESS
Definition WM_api.hh:1566
#define NC_NODE
Definition WM_types.hh:361
#define ND_DISPLAY
Definition WM_types.hh:458
#define ND_MODIFIER
Definition WM_types.hh:429
@ WM_OP_EXEC_REGION_WIN
Definition WM_types.hh:226
@ WM_OP_EXEC_DEFAULT
Definition WM_types.hh:225
#define ND_SPACE_VIEW3D
Definition WM_types.hh:494
#define NC_OBJECT
Definition WM_types.hh:346
#define NS_VIEW3D_SHADING
Definition WM_types.hh:543
#define NC_SPACE
Definition WM_types.hh:359
volatile int lock
SIMD_FORCE_INLINE btScalar norm() const
Return the norm (length) of the vector.
Definition btVector3.h:263
const Value * lookup_ptr(const Key &key) const
Definition BLI_map.hh:484
Value & lookup_or_add_default(const Key &key)
Definition BLI_map.hh:601
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:531
ItemIterator items() const
Definition BLI_map.hh:864
auto add_or_modify(const Key &key, const CreateValueF &create_value, const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
Definition BLI_map.hh:457
Value & lookup_or_add(const Key &key, const Value &value)
Definition BLI_map.hh:551
constexpr bool is_empty() const
constexpr const char * c_str() const
void append(const T &value)
bool is_empty() const
local_group_size(16, 16) .push_constant(Type b
const Depsgraph * depsgraph
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
static const char * modifier_name[LS_MODIFIER_NUM]
Definition linestyle.cc:680
#define G(x, y, z)
std::optional< NodesModifierBakeTarget > get_node_bake_target(const Object &object, const NodesModifierData &nmd, int node_id)
std::string get_default_modifier_bake_directory(const Main &bmain, const Object &object, const NodesModifierData &nmd)
std::optional< BakePath > get_node_bake_path(const Main &bmain, const Object &object, const NodesModifierData &nmd, int node_id)
std::optional< IndexRange > get_node_bake_frame_range(const Scene &scene, const Object &object, const NodesModifierData &nmd, int node_id)
void serialize_bake(const BakeState &bake_state, BlobWriter &blob_writer, BlobWriteSharing &blob_sharing, std::ostream &r_stream)
UnpackGeometryNodesBakeResult unpack_geometry_nodes_bake(Main &bmain, ReportList *reports, Object &object, NodesModifierData &nmd, NodesModifierBake &bake, ePF_FileStatus how)
PackGeometryNodesBakeResult pack_geometry_nodes_bake(Main &bmain, ReportList *reports, Object &object, NodesModifierData &nmd, NodesModifierBake &bake)
std::string frame_to_file_name(const SubFrame &frame)
std::optional< std::string > get_modifier_bake_path(const Main &bmain, const Object &object, const NodesModifierData &nmd)
void clear(T **items, int *items_num, int *active_index, void(*destruct_item)(T *))
static int delete_single_bake_exec(bContext *C, wmOperator *op)
void OBJECT_OT_simulation_nodes_cache_bake(wmOperatorType *ot)
static void bake_geometry_nodes_startjob(void *customdata, wmJobWorkerStatus *worker_status)
static void clear_requested_bakes_in_modifier_cache(BakeGeometryNodesJob &job)
static void bake_geometry_nodes_endjob(void *customdata)
static void simulate_to_frame_endjob(void *customdata)
static int bake_simulation_modal(bContext *C, wmOperator *, const wmEvent *)
static void bake_simulation_validate_paths(bContext *C, wmOperator *op, const Span< Object * > objects)
static void try_delete_bake(bContext *C, Object &object, NodesModifierData &nmd, const int bake_id, ReportList *reports)
static int unpack_single_bake_exec(bContext *C, wmOperator *op)
static int bake_single_node_exec(bContext *C, wmOperator *op)
static void simulate_to_frame_startjob(void *customdata, wmJobWorkerStatus *worker_status)
static int bake_simulation_exec(bContext *C, wmOperator *op)
void OBJECT_OT_geometry_node_bake_delete_single(wmOperatorType *ot)
void OBJECT_OT_geometry_node_bake_unpack_single(wmOperatorType *ot)
static void single_bake_operator_props(wmOperatorType *ot)
void OBJECT_OT_geometry_node_bake_pack_single(wmOperatorType *ot)
static void initialize_modifier_bake_directory_if_necessary(bContext *C, Object &object, NodesModifierData &nmd, wmOperator *op)
static int bake_single_node_modal(bContext *C, wmOperator *, const wmEvent *)
static Vector< NodeBakeRequest > bake_simulation_gather_requests(bContext *C, wmOperator *op)
static int unpack_single_bake_invoke(bContext *C, wmOperator *op, const wmEvent *)
static PathUsersMap bake_simulation_get_path_users(bContext *C, const Span< Object * > objects)
static bool may_have_disk_bake(const NodesModifierData &nmd)
void OBJECT_OT_geometry_node_bake_single(wmOperatorType *ot)
static int start_bake_job(bContext *C, Vector< NodeBakeRequest > requests, wmOperator *op, const BakeRequestsMode mode)
static int delete_baked_simulation_exec(bContext *C, wmOperator *op)
static int bake_simulation_invoke(bContext *C, wmOperator *op, const wmEvent *)
static int simulate_to_frame_modal(bContext *C, wmOperator *, const wmEvent *)
static Vector< NodeBakeRequest > collect_simulations_to_bake(Main &bmain, Scene &scene, const Span< Object * > objects)
static int simulate_to_frame_invoke(bContext *C, wmOperator *op, const wmEvent *)
static void request_bakes_in_modifier_cache(BakeGeometryNodesJob &job)
void OBJECT_OT_simulation_nodes_cache_calculate_to_frame(wmOperatorType *ot)
static void reset_old_bake_cache(NodeBakeRequest &request)
static bool bake_directory_has_data(const StringRefNull absolute_bake_dir)
static Vector< NodeBakeRequest > bake_single_node_gather_bake_request(bContext *C, wmOperator *op)
static int bake_single_node_invoke(bContext *C, wmOperator *op, const wmEvent *)
static int pack_single_bake_exec(bContext *C, wmOperator *op)
void OBJECT_OT_simulation_nodes_cache_delete(wmOperatorType *ot)
static void clear_data_block_references(NodesModifierBake &bake)
Object * context_active_object(const bContext *C)
uint64_t get_default_hash(const T &v)
Definition BLI_hash.hh:219
constexpr int64_t default_inline_buffer_capacity(size_t element_size)
PythonProbingStrategy<> DefaultProbingStrategy
void nodes_modifier_packed_bake_free(NodesModifierPackedBake *packed_bake)
int RNA_int_get(PointerRNA *ptr, const char *name)
char * RNA_string_get_alloc(PointerRNA *ptr, const char *name, char *fixedbuf, int fixedlen, int *r_len)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
#define INT32_MAX
Definition stdint.h:137
__int64 int64_t
Definition stdint.h:89
#define INT32_MIN
Definition stdint.h:136
unsigned __int64 uint64_t
Definition stdint.h:90
struct bNodeTree * node_group
NodesModifierRuntimeHandle * runtime
NodesModifierBake * bakes
NodesModifierBakeFile * meta_files
NodesModifierBakeFile * blob_files
void * data
Definition RNA_types.hh:42
struct RenderData r
Map< int, std::unique_ptr< SimulationNodeCache > > simulation_cache_by_id
Map< int, std::unique_ptr< BakeNodeCache > > bake_cache_by_id
NodeBakeCache * get_node_bake_cache(const int id)
Vector< std::unique_ptr< FrameCache > > frames
std::unique_ptr< bake::BlobWriteSharing > blob_sharing
bool operator()(const StringRef a, const StringRef b) const
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
StructRNA * srna
Definition WM_types.hh:1080
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
void WM_main_add_notifier(uint type, void *reference)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_set_locked_interface(wmWindowManager *wm, bool lock)
wmOperatorType * ot
Definition wm_files.cc:4125
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
Definition wm_jobs.cc:352
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:455
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:189
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:364
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:223
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:336
ID * WM_operator_properties_id_lookup_from_name_or_session_uid(Main *bmain, PointerRNA *ptr, const ID_Type type)
void WM_operator_properties_id_lookup(wmOperatorType *ot, const bool add_name_prop)
int WM_operator_confirm_ex(bContext *C, wmOperator *op, const char *title, const char *message, const char *confirm_text, int icon, bool cancel_default)