Blender V4.3
node_geo_bake.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 <fmt/format.h>
6
7#include "NOD_geo_bake.hh"
9#include "NOD_rna_define.hh"
12
13#include "UI_interface.hh"
14#include "UI_resources.hh"
15
16#include "BLI_path_utils.hh"
17#include "BLI_string.h"
18
22#include "BKE_context.hh"
23#include "BKE_global.hh"
24#include "BKE_main.hh"
25#include "BKE_screen.hh"
26
27#include "ED_node.hh"
28
29#include "DNA_modifier_types.h"
30
31#include "RNA_access.hh"
32#include "RNA_prototypes.hh"
33
34#include "MOD_nodes.hh"
35
36#include "WM_api.hh"
37
38#include "BLO_read_write.hh"
39
40#include "node_geometry_util.hh"
41
43
44namespace bake = bke::bake;
45
47
49{
50 b.use_custom_socket_order();
51 b.allow_any_socket_order();
52
53 const bNodeTree *ntree = b.tree_or_null();
54 const bNode *node = b.node_or_null();
55 if (!node) {
56 return;
57 }
58 const NodeGeometryBake &storage = node_storage(*node);
59
60 for (const int i : IndexRange(storage.items_num)) {
61 const NodeGeometryBakeItem &item = storage.items[i];
62 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
63 const StringRef name = item.name;
64 const std::string identifier = BakeItemsAccessor::socket_identifier_for_item(item);
65 auto &input_decl = b.add_input(socket_type, name, identifier)
66 .socket_name_ptr(
67 &ntree->id, BakeItemsAccessor::item_srna, &item, "name");
68 auto &output_decl = b.add_output(socket_type, name, identifier).align_with_previous();
69 if (socket_type_supports_fields(socket_type)) {
70 input_decl.supports_field();
72 output_decl.field_source();
73 }
74 else {
75 output_decl.dependent_field({input_decl.index()});
76 }
77 }
78 }
79 b.add_input<decl::Extend>("", "__extend__");
80 b.add_output<decl::Extend>("", "__extend__").align_with_previous();
81}
82
83static void node_init(bNodeTree * /*tree*/, bNode *node)
84{
85 NodeGeometryBake *data = MEM_cnew<NodeGeometryBake>(__func__);
86
87 data->items = MEM_cnew_array<NodeGeometryBakeItem>(1, __func__);
88 data->items_num = 1;
89
90 NodeGeometryBakeItem &item = data->items[0];
91 item.name = BLI_strdup(DATA_("Geometry"));
92 item.identifier = data->next_identifier++;
93 item.attribute_domain = int16_t(AttrDomain::Point);
95
96 node->storage = data;
97}
98
104
105static void node_copy_storage(bNodeTree * /*tree*/, bNode *dst_node, const bNode *src_node)
106{
107 const NodeGeometryBake &src_storage = node_storage(*src_node);
108 auto *dst_storage = MEM_cnew<NodeGeometryBake>(__func__, src_storage);
109 dst_node->storage = dst_storage;
110
112}
113
114static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
115{
117 *ntree, *node, *node, *link);
118}
119
120static const CPPType &get_item_cpp_type(const eNodeSocketDatatype socket_type)
121{
122 const char *socket_idname = bke::node_static_socket_type(socket_type, 0);
123 const bke::bNodeSocketType *typeinfo = bke::node_socket_type_find(socket_idname);
124 BLI_assert(typeinfo);
126 return *typeinfo->geometry_nodes_cpp_type;
127}
128
129static void draw_bake_item(uiList * /*ui_list*/,
130 const bContext *C,
131 uiLayout *layout,
132 PointerRNA * /*idataptr*/,
133 PointerRNA *itemptr,
134 int /*icon*/,
135 PointerRNA * /*active_dataptr*/,
136 const char * /*active_propname*/,
137 int /*index*/,
138 int /*flt_flag*/)
139{
140 uiLayout *row = uiLayoutRow(layout, true);
142 RNA_float_get_array(itemptr, "color", color);
143 uiTemplateNodeSocket(row, const_cast<bContext *>(C), color);
145 uiItemR(row, itemptr, "name", UI_ITEM_NONE, "", ICON_NONE);
146}
147
148static void draw_bake_items(const bContext *C, uiLayout *layout, PointerRNA node_ptr)
149{
150 static const uiListType *bake_items_list = []() {
151 uiListType *list = MEM_cnew<uiListType>(__func__);
152 STRNCPY(list->idname, "DATA_UL_bake_node_items");
154 WM_uilisttype_add(list);
155 return list;
156 }();
157
158 bNode &node = *static_cast<bNode *>(node_ptr.data);
159
160 if (uiLayout *panel = uiLayoutPanel(C, layout, "bake_items", false, TIP_("Bake Items"))) {
161 uiLayout *row = uiLayoutRow(panel, false);
162 uiTemplateList(row,
163 C,
164 bake_items_list->idname,
165 "",
166 &node_ptr,
167 "bake_items",
168 &node_ptr,
169 "active_index",
170 nullptr,
171 3,
172 5,
174 0,
176
177 {
178 uiLayout *ops_col = uiLayoutColumn(row, false);
179 {
180 uiLayout *add_remove_col = uiLayoutColumn(ops_col, true);
181 uiItemO(add_remove_col, "", ICON_ADD, "node.bake_node_item_add");
182 uiItemO(add_remove_col, "", ICON_REMOVE, "node.bake_node_item_remove");
183 }
184 {
185 uiLayout *up_down_col = uiLayoutColumn(ops_col, true);
186 uiItemEnumO(up_down_col, "node.bake_node_item_move", "", ICON_TRIA_UP, "direction", 0);
187 uiItemEnumO(up_down_col, "node.bake_node_item_move", "", ICON_TRIA_DOWN, "direction", 1);
188 }
189 }
190
191 NodeGeometryBake &storage = node_storage(node);
192 if (storage.active_index >= 0 && storage.active_index < storage.items_num) {
193 NodeGeometryBakeItem &active_item = storage.items[storage.active_index];
195 node_ptr.owner_id, BakeItemsAccessor::item_srna, &active_item);
196 uiLayoutSetPropSep(panel, true);
197 uiLayoutSetPropDecorate(panel, false);
198 uiItemR(panel, &item_ptr, "socket_type", UI_ITEM_NONE, nullptr, ICON_NONE);
200 uiItemR(panel, &item_ptr, "attribute_domain", UI_ITEM_NONE, nullptr, ICON_NONE);
201 uiItemR(panel, &item_ptr, "is_attribute", UI_ITEM_NONE, nullptr, ICON_NONE);
202 }
203 }
204 }
205}
206
208{
210 ot, "Remove Bake Item", __func__, "Remove active bake item");
211}
212
214{
215 socket_items::ops::add_item<BakeItemsAccessor>(ot, "Add Bake Item", __func__, "Add bake item");
216}
217
219{
221 ot, "Move Bake Item", __func__, "Move active bake item");
222}
223
230
232{
234 const int items_num = bake_items.size();
235 config.domains.resize(items_num);
236 config.names.resize(items_num);
237 config.types.resize(items_num);
238 config.geometries_by_attribute.resize(items_num);
239
240 int last_geometry_index = -1;
241 for (const int item_i : bake_items.index_range()) {
242 const NodeGeometryBakeItem &item = bake_items[item_i];
243 config.types[item_i] = eNodeSocketDatatype(item.socket_type);
244 config.names[item_i] = item.name;
245 config.domains[item_i] = AttrDomain(item.attribute_domain);
246 if (item.socket_type == SOCK_GEOMETRY) {
247 last_geometry_index = item_i;
248 }
249 else if (last_geometry_index != -1) {
250 config.geometries_by_attribute[item_i].append(last_geometry_index);
251 }
252 }
253 return config;
254}
255
261 private:
262 std::mutex mutex_;
264
265 public:
267 {
268 std::lock_guard lock{mutex_};
269 return map_.lookup_default(key, nullptr);
270 }
271
272 void try_add(ID &id) override
273 {
274 std::lock_guard lock{mutex_};
275 map_.add(bake::BakeDataBlockID(id), &id);
276 }
277};
278
280 const bNode &node_;
281 Span<NodeGeometryBakeItem> bake_items_;
282 bake::BakeSocketConfig bake_socket_config_;
283
284 public:
286 : node_(node)
287 {
288 debug_name_ = "Bake";
289 const NodeGeometryBake &storage = node_storage(node);
290 bake_items_ = {storage.items, storage.items_num};
291
292 MutableSpan<int> lf_index_by_bsocket = lf_graph_info.mapping.lf_index_by_bsocket;
293
294 for (const int i : bake_items_.index_range()) {
295 const NodeGeometryBakeItem &item = bake_items_[i];
296 const bNodeSocket &input_bsocket = node.input_socket(i);
297 const bNodeSocket &output_bsocket = node.output_socket(i);
299 lf_index_by_bsocket[input_bsocket.index_in_tree()] = inputs_.append_and_get_index_as(
300 item.name, type, lf::ValueUsage::Maybe);
301 lf_index_by_bsocket[output_bsocket.index_in_tree()] = outputs_.append_and_get_index_as(
302 item.name, type);
303 }
304
305 bake_socket_config_ = make_bake_socket_config(bake_items_);
306 }
307
308 void execute_impl(lf::Params &params, const lf::Context &context) const final
309 {
310 GeoNodesLFUserData &user_data = *static_cast<GeoNodesLFUserData *>(context.user_data);
311 GeoNodesLFLocalUserData &local_user_data = *static_cast<GeoNodesLFLocalUserData *>(
312 context.local_user_data);
313 if (!user_data.call_data->self_object()) {
314 /* The self object is currently required for generating anonymous attribute names. */
316 return;
317 }
318 if (!user_data.call_data->bake_params) {
320 return;
321 }
322 std::optional<FoundNestedNodeID> found_id = find_nested_node_id(user_data, node_.identifier);
323 if (!found_id) {
325 return;
326 }
327 if (found_id->is_in_loop) {
328 DummyDataBlockMap data_block_map;
329 this->pass_through(params, user_data, &data_block_map);
330 return;
331 }
332 BakeNodeBehavior *behavior = user_data.call_data->bake_params->get(found_id->id);
333 if (!behavior) {
335 return;
336 }
337 if (auto *info = std::get_if<sim_output::ReadSingle>(&behavior->behavior)) {
338 this->output_cached_state(params, user_data, behavior->data_block_map, info->state);
339 }
340 else if (auto *info = std::get_if<sim_output::ReadInterpolated>(&behavior->behavior)) {
342 behavior->data_block_map,
343 *user_data.call_data->self_object(),
344 *user_data.compute_context,
345 info->prev_state,
346 info->next_state,
347 info->mix_factor);
348 }
349 else if (std::get_if<sim_output::PassThrough>(&behavior->behavior)) {
350 this->pass_through(params, user_data, behavior->data_block_map);
351 }
352 else if (auto *info = std::get_if<sim_output::StoreNewState>(&behavior->behavior)) {
353 this->store(params, user_data, behavior->data_block_map, *info);
354 }
355 else if (auto *info = std::get_if<sim_output::ReadError>(&behavior->behavior)) {
356 if (geo_eval_log::GeoTreeLogger *tree_logger = local_user_data.try_get_tree_logger(
357 user_data))
358 {
359 tree_logger->node_warnings.append(
360 *tree_logger->allocator, {node_.identifier, {NodeWarningType::Error, info->message}});
361 }
363 }
364 else {
366 }
367 }
368
373
375 GeoNodesLFUserData &user_data,
376 bke::bake::BakeDataBlockMap *data_block_map) const
377 {
378 std::optional<bake::BakeState> bake_state = this->get_bake_state_from_inputs(params,
379 data_block_map);
380 if (!bake_state) {
381 /* Wait for inputs to be computed. */
382 return;
383 }
384 Array<void *> output_values(bake_items_.size());
385 for (const int i : bake_items_.index_range()) {
386 output_values[i] = params.get_output_data_ptr(i);
387 }
388 this->move_bake_state_to_values(std::move(*bake_state),
389 data_block_map,
390 *user_data.call_data->self_object(),
391 *user_data.compute_context,
392 output_values);
393 for (const int i : bake_items_.index_range()) {
394 params.output_set(i);
395 }
396 }
397
399 GeoNodesLFUserData &user_data,
400 bke::bake::BakeDataBlockMap *data_block_map,
401 const sim_output::StoreNewState &info) const
402 {
403 std::optional<bake::BakeState> bake_state = this->get_bake_state_from_inputs(params,
404 data_block_map);
405 if (!bake_state) {
406 /* Wait for inputs to be computed. */
407 return;
408 }
409 this->output_cached_state(params, user_data, data_block_map, *bake_state);
410 info.store_fn(std::move(*bake_state));
411 }
412
414 GeoNodesLFUserData &user_data,
415 bke::bake::BakeDataBlockMap *data_block_map,
416 const bake::BakeStateRef &bake_state) const
417 {
418 Array<void *> output_values(bake_items_.size());
419 for (const int i : bake_items_.index_range()) {
420 output_values[i] = params.get_output_data_ptr(i);
421 }
422 this->copy_bake_state_to_values(bake_state,
423 data_block_map,
424 *user_data.call_data->self_object(),
425 *user_data.compute_context,
426 output_values);
427 for (const int i : bake_items_.index_range()) {
428 params.output_set(i);
429 }
430 }
431
433 bke::bake::BakeDataBlockMap *data_block_map,
434 const Object &self_object,
435 const ComputeContext &compute_context,
436 const bake::BakeStateRef &prev_state,
438 const float mix_factor) const
439 {
440 Array<void *> output_values(bake_items_.size());
441 for (const int i : bake_items_.index_range()) {
442 output_values[i] = params.get_output_data_ptr(i);
443 }
445 prev_state, data_block_map, self_object, compute_context, output_values);
446
447 Array<void *> next_values(bake_items_.size());
448 LinearAllocator<> allocator;
449 for (const int i : bake_items_.index_range()) {
450 const CPPType &type = *outputs_[i].type;
451 next_values[i] = allocator.allocate(type.size(), type.alignment());
452 }
454 next_state, data_block_map, self_object, compute_context, next_values);
455
456 for (const int i : bake_items_.index_range()) {
457 mix_baked_data_item(eNodeSocketDatatype(bake_items_[i].socket_type),
458 output_values[i],
459 next_values[i],
460 mix_factor);
461 }
462
463 for (const int i : bake_items_.index_range()) {
464 const CPPType &type = *outputs_[i].type;
465 type.destruct(next_values[i]);
466 }
467
468 for (const int i : bake_items_.index_range()) {
469 params.output_set(i);
470 }
471 }
472
473 std::optional<bake::BakeState> get_bake_state_from_inputs(
474 lf::Params &params, bke::bake::BakeDataBlockMap *data_block_map) const
475 {
476 Array<void *> input_values(bake_items_.size());
477 for (const int i : bake_items_.index_range()) {
478 input_values[i] = params.try_get_input_data_ptr_or_request(i);
479 }
480 if (input_values.as_span().contains(nullptr)) {
481 /* Wait for inputs to be computed. */
482 return std::nullopt;
483 }
484
486 input_values, bake_socket_config_, data_block_map);
487
488 bake::BakeState bake_state;
489 for (const int i : bake_items_.index_range()) {
490 const NodeGeometryBakeItem &item = bake_items_[i];
491 std::unique_ptr<bake::BakeItem> &bake_item = bake_items[i];
492 if (bake_item) {
493 bake_state.items_by_id.add_new(item.identifier, std::move(bake_item));
494 }
495 }
496 return bake_state;
497 }
498
500 bke::bake::BakeDataBlockMap *data_block_map,
501 const Object &self_object,
502 const ComputeContext &compute_context,
503 Span<void *> r_output_values) const
504 {
505 Vector<bake::BakeItem *> bake_items;
506 for (const NodeGeometryBakeItem &item : bake_items_) {
507 std::unique_ptr<bake::BakeItem> *bake_item = bake_state.items_by_id.lookup_ptr(
508 item.identifier);
509 bake_items.append(bake_item ? bake_item->get() : nullptr);
510 }
512 bake_items,
513 bake_socket_config_,
514 data_block_map,
515 [&](const int i, const CPPType &type) {
516 return this->make_attribute_field(self_object, compute_context, bake_items_[i], type);
517 },
518 r_output_values);
519 }
520
522 bke::bake::BakeDataBlockMap *data_block_map,
523 const Object &self_object,
524 const ComputeContext &compute_context,
525 Span<void *> r_output_values) const
526 {
528 for (const NodeGeometryBakeItem &item : bake_items_) {
529 const bake::BakeItem *const *bake_item = bake_state.items_by_id.lookup_ptr(item.identifier);
530 bake_items.append(bake_item ? *bake_item : nullptr);
531 }
533 bake_items,
534 bake_socket_config_,
535 data_block_map,
536 [&](const int i, const CPPType &type) {
537 return this->make_attribute_field(self_object, compute_context, bake_items_[i], type);
538 },
539 r_output_values);
540 }
541
542 std::shared_ptr<AttributeFieldInput> make_attribute_field(const Object &self_object,
543 const ComputeContext &compute_context,
544 const NodeGeometryBakeItem &item,
545 const CPPType &type) const
546 {
547 std::string attribute_name = bke::hash_to_anonymous_attribute_name(
548 compute_context.hash(), self_object.id.name, node_.identifier, item.identifier);
549 std::string socket_inspection_name = make_anonymous_attribute_socket_inspection_string(
550 node_.label_or_name(), item.name);
551 return std::make_shared<AttributeFieldInput>(
552 std::move(attribute_name), type, std::move(socket_inspection_name));
553 }
554};
555
557{
558 BakeDrawContext ctx;
559 if (!get_bake_draw_context(&params.C, params.node, ctx)) {
560 return;
561 }
562 if (ctx.is_baked) {
564 row.text = get_baked_string(ctx);
565 params.rows.append(std::move(row));
566 }
567}
568
569static void node_layout(uiLayout *layout, bContext *C, PointerRNA *ptr)
570{
571 BakeDrawContext ctx;
572 const bNode &node = *static_cast<const bNode *>(ptr->data);
573 if (!get_bake_draw_context(C, node, ctx)) {
574 return;
575 }
576
578 uiLayout *col = uiLayoutColumn(layout, false);
579 {
580 uiLayout *row = uiLayoutRow(col, true);
581 uiLayoutSetEnabled(row, !ctx.is_baked);
582 uiItemR(row, &ctx.bake_rna, "bake_mode", UI_ITEM_R_EXPAND, IFACE_("Mode"), ICON_NONE);
583 }
585}
586
588{
589 draw_bake_items(C, layout, *ptr);
590
591 BakeDrawContext ctx;
592 const bNode &node = *static_cast<const bNode *>(ptr->data);
593 if (!get_bake_draw_context(C, node, ctx)) {
594 return;
595 }
596
598
599 {
600 uiLayout *col = uiLayoutColumn(layout, false);
601 {
602 uiLayout *row = uiLayoutRow(col, true);
603 uiLayoutSetEnabled(row, !ctx.is_baked);
604 uiItemR(row, &ctx.bake_rna, "bake_mode", UI_ITEM_R_EXPAND, IFACE_("Mode"), ICON_NONE);
605 }
606
607 draw_bake_button_row(ctx, col, true);
608 if (const std::optional<std::string> bake_state_str = get_bake_state_string(ctx)) {
609 uiLayout *row = uiLayoutRow(col, true);
610 uiItemL(row, bake_state_str->c_str(), ICON_NONE);
611 }
612 }
613
614 draw_common_bake_settings(C, ctx, layout);
615 draw_data_blocks(C, layout, ctx.bake_rna);
616}
617
619{
620 const eNodeSocketDatatype type = eNodeSocketDatatype(params.other_socket().type);
621 if (type == SOCK_GEOMETRY) {
622 params.add_item(IFACE_("Geometry"), [](LinkSearchOpParams &params) {
623 bNode &node = params.add_node("GeometryNodeBake");
624 params.connect_available_socket(node, "Geometry");
625 });
626 return;
627 }
629 return;
630 }
631
632 params.add_item(IFACE_("Value"), [type](LinkSearchOpParams &params) {
633 bNode &node = params.add_node("GeometryNodeBake");
635 node, type, params.socket.name);
636 params.update_and_connect_available_socket(node, params.socket.name);
637 });
638}
639
657NOD_REGISTER_NODE(node_register)
658
659} // namespace blender::nodes::node_geo_bake_cc
660
661namespace blender::nodes {
662
663bool get_bake_draw_context(const bContext *C, const bNode &node, BakeDrawContext &r_ctx)
664{
666 r_ctx.node = &node;
667 r_ctx.snode = CTX_wm_space_node(C);
668 if (!r_ctx.snode) {
669 return false;
670 }
671 std::optional<ed::space_node::ObjectAndModifier> object_and_modifier =
673 if (!object_and_modifier) {
674 return false;
675 }
676 r_ctx.object = object_and_modifier->object;
677 r_ctx.nmd = object_and_modifier->nmd;
678 const std::optional<int32_t> bake_id = ed::space_node::find_nested_node_id_in_root(*r_ctx.snode,
679 *r_ctx.node);
680 if (!bake_id) {
681 return false;
682 }
683 r_ctx.bake = nullptr;
684 for (const NodesModifierBake &iter_bake : Span(r_ctx.nmd->bakes, r_ctx.nmd->bakes_num)) {
685 if (iter_bake.id == *bake_id) {
686 r_ctx.bake = &iter_bake;
687 break;
688 }
689 }
690 if (!r_ctx.bake) {
691 return false;
692 }
693
695 const_cast<ID *>(&r_ctx.object->id), &RNA_NodesModifierBake, (void *)r_ctx.bake);
696 if (r_ctx.nmd->runtime->cache) {
697 const bke::bake::ModifierCache &cache = *r_ctx.nmd->runtime->cache;
698 std::lock_guard lock{cache.mutex};
699 if (const std::unique_ptr<bke::bake::BakeNodeCache> *node_cache_ptr =
700 cache.bake_cache_by_id.lookup_ptr(*bake_id))
701 {
702 const bke::bake::BakeNodeCache &node_cache = **node_cache_ptr;
703 if (!node_cache.bake.frames.is_empty()) {
704 const int first_frame = node_cache.bake.frames.first()->frame.frame();
705 const int last_frame = node_cache.bake.frames.last()->frame.frame();
706 r_ctx.baked_range = IndexRange(first_frame, last_frame - first_frame + 1);
707 }
708 }
709 else if (const std::unique_ptr<bke::bake::SimulationNodeCache> *node_cache_ptr =
710 cache.simulation_cache_by_id.lookup_ptr(*bake_id))
711 {
712 const bke::bake::SimulationNodeCache &node_cache = **node_cache_ptr;
713 if (!node_cache.bake.frames.is_empty() &&
715 {
716 const int first_frame = node_cache.bake.frames.first()->frame.frame();
717 const int last_frame = node_cache.bake.frames.last()->frame.frame();
718 r_ctx.baked_range = IndexRange(first_frame, last_frame - first_frame + 1);
719 }
720 }
721 }
722 const Scene *scene = CTX_data_scene(C);
724 *scene, *r_ctx.object, *r_ctx.nmd, r_ctx.bake->id);
725 r_ctx.bake_still = node.type == GEO_NODE_BAKE &&
727 r_ctx.is_baked = r_ctx.baked_range.has_value();
728 r_ctx.bake_target = bke::bake::get_node_bake_target(*r_ctx.object, *r_ctx.nmd, r_ctx.bake->id);
729
730 return true;
731}
732
733std::string get_baked_string(const BakeDrawContext &ctx)
734{
735 if (ctx.bake_still && ctx.baked_range->size() == 1) {
736 return fmt::format(RPT_("Baked Frame {}"), ctx.baked_range->first());
737 }
738 return fmt::format(RPT_("Baked {} - {}"), ctx.baked_range->first(), ctx.baked_range->last());
739}
740
741std::optional<std::string> get_bake_state_string(const BakeDrawContext &ctx)
742{
743 if (G.is_rendering) {
744 /* Avoid accessing data that is generated while baking. */
745 return std::nullopt;
746 }
747 if (ctx.is_baked) {
748 const std::string baked_str = get_baked_string(ctx);
750 BLI_str_format_byte_unit(size_str, ctx.bake->bake_size, true);
751 if (ctx.bake->packed) {
752 return fmt::format(RPT_("{} ({} packed)"), baked_str, size_str);
753 }
754 return fmt::format(RPT_("{} ({} on disk)"), baked_str, size_str);
755 }
756 if (ctx.frame_range.has_value()) {
757 if (!ctx.bake_still) {
758 return fmt::format(
759 RPT_("Frames {} - {}"), ctx.frame_range->first(), ctx.frame_range->last());
760 }
761 }
762 return std::nullopt;
763}
764
765void draw_bake_button_row(const BakeDrawContext &ctx, uiLayout *layout, const bool is_in_sidebar)
766{
767 uiLayout *col = uiLayoutColumn(layout, true);
768 uiLayout *row = uiLayoutRow(col, true);
769 {
770 const char *bake_label = IFACE_("Bake");
771 if (is_in_sidebar) {
772 bake_label = ctx.bake_target == NODES_MODIFIER_BAKE_TARGET_DISK ? IFACE_("Bake to Disk") :
773 IFACE_("Bake Packed");
774 }
775
777 uiItemFullO(row,
778 "OBJECT_OT_geometry_node_bake_single",
779 bake_label,
780 ICON_NONE,
781 nullptr,
784 &ptr);
786 RNA_string_set(&ptr, "modifier_name", ctx.nmd->modifier.name);
787 RNA_int_set(&ptr, "bake_id", ctx.bake->id);
788 }
789 {
790 uiLayout *subrow = uiLayoutRow(row, true);
791 uiLayoutSetActive(subrow, ctx.is_baked);
792 if (is_in_sidebar) {
793 if (ctx.is_baked && !G.is_rendering) {
794 if (ctx.bake->packed) {
796 uiItemFullO(subrow,
797 "OBJECT_OT_geometry_node_bake_unpack_single",
798 "",
799 ICON_PACKAGE,
800 nullptr,
803 &ptr);
805 RNA_string_set(&ptr, "modifier_name", ctx.nmd->modifier.name);
806 RNA_int_set(&ptr, "bake_id", ctx.bake->id);
807 }
808 else {
810 uiItemFullO(subrow,
811 "OBJECT_OT_geometry_node_bake_pack_single",
812 "",
813 ICON_UGLYPACKAGE,
814 nullptr,
817 &ptr);
819 RNA_string_set(&ptr, "modifier_name", ctx.nmd->modifier.name);
820 RNA_int_set(&ptr, "bake_id", ctx.bake->id);
821 }
822 }
823 else {
824 /* If the data is not yet baked, still show the icon based on the derived bake target.*/
825 const int icon = ctx.bake_target == NODES_MODIFIER_BAKE_TARGET_DISK ? ICON_UGLYPACKAGE :
826 ICON_PACKAGE;
828 uiItemFullO(subrow,
829 "OBJECT_OT_geometry_node_bake_pack_single",
830 "",
831 icon,
832 nullptr,
835 &ptr);
836 }
837 }
838 {
840 uiItemFullO(subrow,
841 "OBJECT_OT_geometry_node_bake_delete_single",
842 "",
843 ICON_TRASH,
844 nullptr,
847 &ptr);
849 RNA_string_set(&ptr, "modifier_name", ctx.nmd->modifier.name);
850 RNA_int_set(&ptr, "bake_id", ctx.bake->id);
851 }
852 }
853}
854
856{
857 uiLayoutSetPropSep(layout, true);
858 uiLayoutSetPropDecorate(layout, false);
859
860 uiLayout *settings_col = uiLayoutColumn(layout, false);
861 uiLayoutSetActive(settings_col, !ctx.is_baked);
862 {
863 uiLayout *col = uiLayoutColumn(settings_col, true);
864 uiItemR(col, &ctx.bake_rna, "bake_target", UI_ITEM_NONE, nullptr, ICON_NONE);
865 uiLayout *subcol = uiLayoutColumn(col, true);
867 uiItemR(
868 subcol, &ctx.bake_rna, "use_custom_path", UI_ITEM_NONE, IFACE_("Custom Path"), ICON_NONE);
869 uiLayout *subsubcol = uiLayoutColumn(subcol, true);
870 const bool use_custom_path = ctx.bake->flag & NODES_MODIFIER_BAKE_CUSTOM_PATH;
871 uiLayoutSetActive(subsubcol, use_custom_path);
872 Main *bmain = CTX_data_main(C);
873 auto bake_path = bke::bake::get_node_bake_path(*bmain, *ctx.object, *ctx.nmd, ctx.bake->id);
874
875 char placeholder_path[FILE_MAX] = "";
876 if (StringRef(ctx.bake->directory).is_empty() &&
877 !(ctx.bake->flag & NODES_MODIFIER_BAKE_CUSTOM_PATH) && bake_path.has_value() &&
878 bake_path->bake_dir.has_value())
879 {
880 STRNCPY(placeholder_path, bake_path->bake_dir->c_str());
882 BLI_path_rel(placeholder_path, BKE_main_blendfile_path(bmain));
883 }
884 }
885
886 uiItemFullR(subsubcol,
887 &ctx.bake_rna,
888 RNA_struct_find_property(&ctx.bake_rna, "directory"),
889 -1,
890 0,
892 IFACE_("Path"),
893 ICON_NONE,
894 placeholder_path);
895 }
896 {
897 uiLayout *col = uiLayoutColumn(settings_col, true);
898 uiItemR(col,
899 &ctx.bake_rna,
900 "use_custom_simulation_frame_range",
902 IFACE_("Custom Range"),
903 ICON_NONE);
904 uiLayout *subcol = uiLayoutColumn(col, true);
906 uiItemR(subcol, &ctx.bake_rna, "frame_start", UI_ITEM_NONE, IFACE_("Start"), ICON_NONE);
907 uiItemR(subcol, &ctx.bake_rna, "frame_end", UI_ITEM_NONE, IFACE_("End"), ICON_NONE);
908 }
909}
910
911static void draw_bake_data_block_list_item(uiList * /*ui_list*/,
912 const bContext * /*C*/,
913 uiLayout *layout,
914 PointerRNA * /*idataptr*/,
915 PointerRNA *itemptr,
916 int /*icon*/,
917 PointerRNA * /*active_dataptr*/,
918 const char * /*active_propname*/,
919 int /*index*/,
920 int /*flt_flag*/)
921{
922 auto &data_block = *static_cast<NodesModifierDataBlock *>(itemptr->data);
923 uiLayout *row = uiLayoutRow(layout, true);
924
925 std::string name;
926 if (StringRef(data_block.lib_name).is_empty()) {
927 name = data_block.id_name;
928 }
929 else {
930 name = fmt::format("{} [{}]", data_block.id_name, data_block.lib_name);
931 }
932
933 uiItemR(row, itemptr, "id", UI_ITEM_NONE, name.c_str(), ICON_NONE);
934}
935
936void draw_data_blocks(const bContext *C, uiLayout *layout, PointerRNA &bake_rna)
937{
938 static const uiListType *data_block_list = []() {
939 uiListType *list = MEM_cnew<uiListType>(__func__);
940 STRNCPY(list->idname, "DATA_UL_nodes_modifier_data_blocks");
942 WM_uilisttype_add(list);
943 return list;
944 }();
945
946 PointerRNA data_blocks_ptr = RNA_pointer_create(
947 bake_rna.owner_id, &RNA_NodesModifierBakeDataBlocks, bake_rna.data);
948
949 if (uiLayout *panel = uiLayoutPanel(
950 C, layout, "data_block_references", true, TIP_("Data-Block References")))
951 {
952 uiTemplateList(panel,
953 C,
954 data_block_list->idname,
955 "",
956 &bake_rna,
957 "data_blocks",
958 &data_blocks_ptr,
959 "active_index",
960 nullptr,
961 3,
962 5,
964 0,
966 }
967}
968
969std::unique_ptr<LazyFunction> get_bake_lazy_function(
970 const bNode &node, GeometryNodesLazyFunctionGraphInfo &lf_graph_info)
971{
972 namespace file_ns = blender::nodes::node_geo_bake_cc;
974 return std::make_unique<file_ns::LazyFunctionForBakeNode>(node, lf_graph_info);
975}
976
977StructRNA *BakeItemsAccessor::item_srna = &RNA_NodeGeometryBakeItem;
979
981{
982 const auto &storage = *static_cast<const NodeGeometryBake *>(node.storage);
983 BLO_write_struct_array(writer, NodeGeometryBakeItem, storage.items_num, storage.items);
984 for (const NodeGeometryBakeItem &item : Span(storage.items, storage.items_num)) {
985 BLO_write_string(writer, item.name);
986 }
987}
988
990{
991 auto &storage = *static_cast<NodeGeometryBake *>(node.storage);
992 BLO_read_struct_array(reader, NodeGeometryBakeItem, storage.items_num, &storage.items);
993 for (const NodeGeometryBakeItem &item : Span(storage.items, storage.items_num)) {
994 BLO_read_string(reader, &item.name);
995 }
996}
997
998}; // namespace blender::nodes
SpaceNode * CTX_wm_space_node(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:832
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1799
#define NODE_CLASS_GEOMETRY
Definition BKE_node.hh:418
#define GEO_NODE_SIMULATION_OUTPUT
Definition BKE_node.hh:1331
#define GEO_NODE_BAKE
Definition BKE_node.hh:1350
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define final(a, b, c)
Definition BLI_hash.h:23
#define FILE_MAX
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
bool void BLI_path_rel(char path[FILE_MAX], const char *basepath) 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
#define BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE
Definition BLI_string.h:28
void BLI_str_format_byte_unit(char dst[BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE], long long int bytes, bool base_10) ATTR_NONNULL(1)
Definition string.c:1192
#define ELEM(...)
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
Definition readfile.cc:4992
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
#define RPT_(msgid)
#define TIP_(msgid)
#define IFACE_(msgid)
#define DATA_(msgid)
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:658
@ NODES_MODIFIER_BAKE_TARGET_DISK
@ NODES_MODIFIER_BAKE_CUSTOM_PATH
@ NODES_MODIFIER_BAKE_CUSTOM_SIMULATION_FRAME_RANGE
@ NODES_MODIFIER_BAKE_MODE_STILL
@ GEO_NODE_BAKE_ITEM_IS_ATTRIBUTE
eNodeSocketDatatype
@ SOCK_GEOMETRY
@ UILST_LAYOUT_DEFAULT
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define C
Definition RandGen.cpp:29
void uiLayoutSetActive(uiLayout *layout, bool active)
@ UI_EMBOSS_NONE
void uiLayoutSetEnabled(uiLayout *layout, bool enabled)
void uiItemL(uiLayout *layout, const char *name, int icon)
void uiItemFullO(uiLayout *layout, const char *opname, const char *name, int icon, IDProperty *properties, wmOperatorCallContext context, eUI_Item_Flag flag, PointerRNA *r_opptr)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, const char *name, int icon, const char *placeholder=nullptr)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemEnumO(uiLayout *layout, const char *opname, const char *name, int icon, const char *propname, int value)
void uiTemplateList(uiLayout *layout, const bContext *C, const char *listtype_name, const char *list_id, PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr, const char *active_propname, const char *item_dyntip_propname, int rows, int maxrows, int layout_type, int columns, enum uiTemplateListFlags flags)
#define UI_ITEM_NONE
PanelLayout uiLayoutPanel(const bContext *C, uiLayout *layout, const char *idname, bool default_closed)
void uiTemplateNodeSocket(uiLayout *layout, bContext *C, const float color[4])
void uiLayoutSetEmboss(uiLayout *layout, eUIEmbossType emboss)
void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
@ UI_TEMPLATE_LIST_FLAG_NONE
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ UI_ITEM_R_EXPAND
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:218
volatile int lock
void resize(const int64_t new_size)
Span< T > as_span() const
Definition BLI_array.hh:232
void destruct(void *ptr) const
int64_t size() const
int64_t alignment() const
const ComputeContextHash & hash() const
void * allocate(const int64_t size, const int64_t alignment)
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
constexpr bool is_empty() const
void append(const T &value)
void resize(const int64_t new_size)
virtual BakeNodeBehavior * get(const int id) const =0
void output_mixed_cached_state(lf::Params &params, bke::bake::BakeDataBlockMap *data_block_map, const Object &self_object, const ComputeContext &compute_context, const bake::BakeStateRef &prev_state, const bake::BakeStateRef &next_state, const float mix_factor) const
void copy_bake_state_to_values(const bake::BakeStateRef &bake_state, bke::bake::BakeDataBlockMap *data_block_map, const Object &self_object, const ComputeContext &compute_context, Span< void * > r_output_values) const
LazyFunctionForBakeNode(const bNode &node, GeometryNodesLazyFunctionGraphInfo &lf_graph_info)
void move_bake_state_to_values(bake::BakeState bake_state, bke::bake::BakeDataBlockMap *data_block_map, const Object &self_object, const ComputeContext &compute_context, Span< void * > r_output_values) const
std::shared_ptr< AttributeFieldInput > make_attribute_field(const Object &self_object, const ComputeContext &compute_context, const NodeGeometryBakeItem &item, const CPPType &type) const
void execute_impl(lf::Params &params, const lf::Context &context) const final
void pass_through(lf::Params &params, GeoNodesLFUserData &user_data, bke::bake::BakeDataBlockMap *data_block_map) const
void store(lf::Params &params, GeoNodesLFUserData &user_data, bke::bake::BakeDataBlockMap *data_block_map, const sim_output::StoreNewState &info) const
std::optional< bake::BakeState > get_bake_state_from_inputs(lf::Params &params, bke::bake::BakeDataBlockMap *data_block_map) const
void output_cached_state(lf::Params &params, GeoNodesLFUserData &user_data, bke::bake::BakeDataBlockMap *data_block_map, const bake::BakeStateRef &bake_state) const
local_group_size(16, 16) .push_constant(Type b
uint col
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
static void next_state()
#define G(x, y, z)
std::optional< NodesModifierBakeTarget > get_node_bake_target(const Object &object, const NodesModifierData &nmd, int node_id)
Array< std::unique_ptr< BakeItem > > move_socket_values_to_bake_items(Span< void * > socket_values, const BakeSocketConfig &config, BakeDataBlockMap *data_block_map)
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 copy_bake_items_to_socket_values(Span< const BakeItem * > bake_items, const BakeSocketConfig &config, BakeDataBlockMap *data_block_map, FunctionRef< std::shared_ptr< AttributeFieldInput >(int, const CPPType &)> make_attribute_field, Span< void * > r_socket_values)
void move_bake_items_to_socket_values(Span< BakeItem * > bake_items, const BakeSocketConfig &config, BakeDataBlockMap *data_block_map, FunctionRef< std::shared_ptr< AttributeFieldInput >(int socket_index, const CPPType &)> make_attribute_field, Span< void * > r_socket_values)
bNodeSocketType * node_socket_type_find(const char *idname)
Definition node.cc:1763
const char * node_static_socket_type(int type, int subtype)
Definition node.cc:2126
void node_type_storage(bNodeType *ntype, const char *storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:4632
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
std::string hash_to_anonymous_attribute_name(Args &&...args)
std::optional< ObjectAndModifier > get_modifier_for_node_editor(const SpaceNode &snode)
std::optional< int32_t > find_nested_node_id_in_root(const SpaceNode &snode, const bNode &node)
static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
static void node_layout(uiLayout *layout, bContext *C, PointerRNA *ptr)
static void draw_bake_item(uiList *, const bContext *C, uiLayout *layout, PointerRNA *, PointerRNA *itemptr, int, PointerRNA *, const char *, int, int)
static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
static void draw_bake_items(const bContext *C, uiLayout *layout, PointerRNA node_ptr)
static const CPPType & get_item_cpp_type(const eNodeSocketDatatype socket_type)
static void NODE_OT_bake_node_item_remove(wmOperatorType *ot)
static bake::BakeSocketConfig make_bake_socket_config(const Span< NodeGeometryBakeItem > bake_items)
static void node_extra_info(NodeExtraInfoParams &params)
static void NODE_OT_bake_node_item_add(wmOperatorType *ot)
static void NODE_OT_bake_node_item_move(wmOperatorType *ot)
static void node_free_storage(bNode *node)
static void node_copy_storage(bNodeTree *, bNode *dst_node, const bNode *src_node)
static void node_declare(NodeDeclarationBuilder &b)
static void node_init(bNodeTree *, bNode *node)
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
void move_active_item(wmOperatorType *ot, const char *name, const char *idname, const char *description)
void remove_active_item(wmOperatorType *ot, const char *name, const char *idname, const char *description)
void add_item(wmOperatorType *ot, const char *name, const char *idname, const char *description)
void copy_array(const bNode &src_node, bNode &dst_node)
Accessor::ItemT * add_item_with_socket_type_and_name(bNode &node, const eNodeSocketDatatype socket_type, const char *name)
bool try_add_item_via_any_extend_socket(bNodeTree &ntree, bNode &extend_node, bNode &storage_node, bNodeLink &link, const std::optional< StringRef > socket_identifier=std::nullopt)
bool get_bake_draw_context(const bContext *C, const bNode &node, BakeDrawContext &r_ctx)
void draw_data_blocks(const bContext *C, uiLayout *layout, PointerRNA &bake_rna)
static void draw_bake_data_block_list_item(uiList *, const bContext *, uiLayout *layout, PointerRNA *, PointerRNA *itemptr, int, PointerRNA *, const char *, int, int)
void draw_common_bake_settings(bContext *C, BakeDrawContext &ctx, uiLayout *layout)
void draw_bake_button_row(const BakeDrawContext &ctx, uiLayout *layout, bool is_in_sidebar=false)
std::string make_anonymous_attribute_socket_inspection_string(const bNodeSocket &socket)
std::unique_ptr< LazyFunction > get_bake_lazy_function(const bNode &node, GeometryNodesLazyFunctionGraphInfo &lf_graph_info)
bool socket_type_supports_fields(const eNodeSocketDatatype socket_type)
void set_default_remaining_node_outputs(lf::Params &params, const bNode &node)
std::optional< FoundNestedNodeID > find_nested_node_id(const GeoNodesLFUserData &user_data, const int node_id)
std::optional< std::string > get_bake_state_string(const BakeDrawContext &ctx)
void mix_baked_data_item(eNodeSocketDatatype socket_type, void *prev, const void *next, const float factor)
std::string get_baked_string(const BakeDrawContext &ctx)
VecBase< float, 4 > float4
void geo_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
signed short int16_t
Definition stdint.h:76
Definition DNA_ID.h:413
char name[66]
Definition DNA_ID.h:425
NodeGeometryBakeItem * items
NodesModifierPackedBake * packed
NodesModifierRuntimeHandle * runtime
NodesModifierBake * bakes
ID * owner_id
Definition RNA_types.hh:40
void * data
Definition RNA_types.hh:42
void * storage
int16_t type
Defines a socket type.
Definition BKE_node.hh:151
const blender::CPPType * geometry_nodes_cpp_type
Definition BKE_node.hh:195
Defines a node type.
Definition BKE_node.hh:218
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:267
void(* draw_buttons_ex)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:240
NodeExtraInfoFunction get_extra_info
Definition BKE_node.hh:366
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:238
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:363
bool(* insert_link)(bNodeTree *ntree, bNode *node, bNodeLink *link)
Definition BKE_node.hh:309
NodeDeclareFunction declare
Definition BKE_node.hh:347
void(* register_operators)()
Definition BKE_node.hh:392
Vector< Vector< int, 1 > > geometries_by_attribute
Map< int, const BakeItem * > items_by_id
Map< int, std::unique_ptr< BakeItem > > items_by_id
Map< int, std::unique_ptr< SimulationNodeCache > > simulation_cache_by_id
Map< int, std::unique_ptr< BakeNodeCache > > bake_cache_by_id
Vector< std::unique_ptr< FrameCache > > frames
std::optional< NodesModifierBakeTarget > bake_target
std::optional< IndexRange > frame_range
const NodesModifierData * nmd
std::optional< IndexRange > baked_range
const NodesModifierBake * bake
static std::string socket_identifier_for_item(const NodeGeometryBakeItem &item)
static void blend_read_data(BlendDataReader *reader, bNode &node)
static void blend_write(BlendWriter *writer, const bNode &node)
static bool supports_socket_type(const eNodeSocketDatatype socket_type)
geo_eval_log::GeoTreeLogger * try_get_tree_logger(const GeoNodesLFUserData &user_data) const
ID * lookup_or_remember_missing(const bake::BakeDataBlockID &key) override
std::function< void(bke::bake::BakeState state)> store_fn
char idname[BKE_ST_MAXNAME]
uiListDrawItemFunc draw_item
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
void WM_operator_properties_id_lookup_set_from_id(PointerRNA *ptr, const ID *id)
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))
bool WM_uilisttype_add(uiListType *ult)