38#include "RNA_prototypes.hh"
69 const int items_num = node_simulation_items.
size();
75 int last_geometry_index = -1;
76 for (
const int item_i : node_simulation_items.
index_range()) {
82 last_geometry_index = item_i;
84 else if (last_geometry_index != -1) {
101 node.label_or_name(), item.
name);
102 return std::make_shared<AttributeFieldInput>(
103 std::move(attribute_name), type, std::move(socket_inspection_name));
108 const Object &self_object,
117 std::unique_ptr<bke::bake::BakeItem> *bake_item = zone_state.
items_by_id.lookup_ptr(
119 bake_items.
append(bake_item ? bake_item->get() :
nullptr);
126 [&](
const int i,
const CPPType &type) {
128 self_object, compute_context, node, node_simulation_items[
i], type);
135 const Object &self_object,
146 bake_items.
append(bake_item ? *bake_item :
nullptr);
153 [&](
const int i,
const CPPType &type) {
155 self_object, compute_context, node, node_simulation_items[
i], type);
171 for (
const int i : node_simulation_items.
index_range()) {
173 std::unique_ptr<bke::bake::BakeItem> &bake_item = bake_items[
i];
187 C,
"simulation_state_items",
false,
IFACE_(
"Simulation State")))
190 C, panel, ntree, output_node);
193 ntree, output_node, [&](
PointerRNA *item_ptr) {
197 panel->prop(item_ptr,
"socket_type",
UI_ITEM_NONE, std::nullopt, ICON_NONE);
199 panel->prop(item_ptr,
"attribute_domain",
UI_ITEM_NONE, std::nullopt, ICON_NONE);
209 bNode *current_node =
static_cast<bNode *
>(current_node_ptr->
data);
242 row->
label(*bake_state_str, ICON_NONE);
265 output_node_id_ = node_storage(node).output_node_id;
266 const bNode &output_node = *node_tree.node_by_id(output_node_id_);
272 lf_index_by_bsocket[node.output_socket(0).index_in_tree()] =
outputs_.append_and_get_index_as(
275 for (
const int i : simulation_items_.index_range()) {
277 const bNodeSocket &input_bsocket = node.input_socket(
i);
278 const bNodeSocket &output_bsocket = node.output_socket(
i + 1);
282 lf_index_by_bsocket[input_bsocket.index_in_tree()] =
inputs_.append_and_get_index_as(
284 lf_index_by_bsocket[output_bsocket.index_in_tree()] =
outputs_.append_and_get_index_as(
301 std::optional<FoundNestedNodeID> found_id =
find_nested_node_id(user_data, output_node_id_);
306 if (found_id->is_in_loop || found_id->is_in_closure) {
312 if (!zone_behavior) {
317 float delta_time = 0.0f;
318 if (
auto *info = std::get_if<sim_input::OutputCopy>(&input_behavior)) {
319 delta_time = info->delta_time;
323 else if (
auto *info = std::get_if<sim_input::OutputMove>(&input_behavior)) {
324 delta_time = info->delta_time;
328 else if (std::get_if<sim_input::PassThrough>(&input_behavior)) {
335 if (!
params.output_was_set(0)) {
351 for (
const int i : simulation_items_.index_range()) {
361 for (
const int i : simulation_items_.index_range()) {
372 for (
const int i : simulation_items_.index_range()) {
376 std::move(zone_state),
382 for (
const int i : simulation_items_.index_range()) {
392 for (
const int i :
inputs_.index_range()) {
393 input_values[
i] =
params.try_get_input_data_ptr_or_request(
i);
395 if (input_values.
as_span().contains(
nullptr)) {
403 simulation_items_, input_values, data_block_map);
410 b.use_custom_socket_order();
411 b.allow_any_socket_order();
414 const bNode *node =
b.node_or_null();
415 const bNodeTree *node_tree =
b.tree_or_null();
416 if (
ELEM(
nullptr, node, node_tree)) {
420 const bNode *output_node = node_tree->node_by_id(node_storage(*node).output_node_id);
427 for (
const int i :
IndexRange(output_storage.items_num)) {
435 auto &input_decl =
b.add_input(socket_type, name, identifier)
438 auto &output_decl =
b.add_output(socket_type, name, identifier).align_with_previous();
441 input_decl.supports_field().structure_type(StructureType::Dynamic);
442 output_decl.dependent_field({input_decl.index()});
445 b.add_input<
decl::Extend>(
"",
"__extend__").structure_type(StructureType::Dynamic);
447 .structure_type(StructureType::Dynamic)
448 .align_with_previous();
455 data->output_node_id = 0;
462 const int label_maxncpy)
469 bNode *output_node = ntree->node_by_id(node_storage(*node).output_node_id);
474 *ntree, *node, *output_node, *link);
481 ntype.
ui_name =
"Simulation Input";
493 "NodeGeometrySimulationInput",
509 int skip_input_index_;
515 int skip_inputs_offset_;
520 int solve_inputs_offset_;
533 const bNodeSocket &skip_bsocket = node.input_socket(0);
534 skip_input_index_ =
inputs_.append_and_get_index_as(
536 lf_index_by_bsocket[skip_bsocket.index_in_tree()] = skip_input_index_;
538 skip_inputs_offset_ =
inputs_.size();
541 for (
const int i : simulation_items_.index_range()) {
547 solve_inputs_offset_ =
inputs_.size();
550 for (
const int i : simulation_items_.index_range()) {
552 const bNodeSocket &input_bsocket = node.input_socket(
i + 1);
553 const bNodeSocket &output_bsocket = node.output_socket(
i);
557 lf_index_by_bsocket[input_bsocket.index_in_tree()] =
inputs_.append_and_get_index_as(
559 lf_index_by_bsocket[output_bsocket.index_in_tree()] =
outputs_.append_and_get_index_as(
568 context.local_user_data);
578 tree_logger->node_warnings.append(
579 *tree_logger->allocator,
581 {NodeWarningType::Error, TIP_(
"Simulation zone is not supported")}});
586 std::optional<FoundNestedNodeID> found_id =
find_nested_node_id(user_data, node_.identifier);
591 if (found_id->is_in_loop || found_id->is_in_closure) {
595 const StringRefNull message =
U.experimental.use_bundle_and_closure_nodes ?
596 TIP_(
"Simulation must not be in a loop or closure") :
597 TIP_(
"Simulation must not be in a loop");
598 tree_logger->node_warnings.append(*tree_logger->allocator,
599 {node_.identifier, {NodeWarningType::Error, message}});
604 SimulationZoneBehavior *zone_behavior = user_data.call_data->simulation_params->get(
606 if (!zone_behavior) {
607 this->set_default_outputs(
params);
611 if (
auto *info = std::get_if<sim_output::ReadSingle>(&output_behavior)) {
612 this->output_cached_state(
params, user_data, zone_behavior->data_block_map, info->state);
614 else if (
auto *info = std::get_if<sim_output::ReadInterpolated>(&output_behavior)) {
615 this->output_mixed_cached_state(
params,
616 zone_behavior->data_block_map,
617 *user_data.call_data->self_object(),
618 *user_data.compute_context,
623 else if (std::get_if<sim_output::PassThrough>(&output_behavior)) {
624 this->pass_through(
params, user_data, zone_behavior->data_block_map);
626 else if (
auto *info = std::get_if<sim_output::StoreNewState>(&output_behavior)) {
627 this->store_new_state(
params, user_data, zone_behavior->data_block_map, *info);
645 for (
const int i : simulation_items_.index_range()) {
646 output_values[
i] =
params.get_output_data_ptr(
i);
655 for (
const int i : simulation_items_.index_range()) {
662 const Object &self_object,
666 const float mix_factor)
const
669 for (
const int i : simulation_items_.index_range()) {
670 output_values[
i] =
params.get_output_data_ptr(
i);
682 for (
const int i : simulation_items_.index_range()) {
684 next_values[
i] = allocator.
allocate(type);
694 for (
const int i : simulation_items_.index_range()) {
701 for (
const int i : simulation_items_.index_range()) {
706 for (
const int i : simulation_items_.index_range()) {
716 params, data_block_map,
true);
723 for (
const int i : simulation_items_.index_range()) {
724 output_values[
i] =
params.get_output_data_ptr(
i);
727 std::move(*bake_state),
733 for (
const int i : simulation_items_.index_range()) {
745 if (skip_variant ==
nullptr) {
749 const bool skip = skip_variant->
get<
bool>();
755 params, data_block_map, skip);
761 info.
store_fn(std::move(*bake_state));
768 const int params_offset = skip ? skip_inputs_offset_ : solve_inputs_offset_;
770 for (
const int i : simulation_items_.index_range()) {
771 input_values[
i] =
params.try_get_input_data_ptr_or_request(
i + params_offset);
773 if (input_values.
as_span().contains(
nullptr)) {
784 b.use_custom_socket_order();
785 b.allow_any_socket_order();
787 "Forward the output of the simulation input node directly to the output node and ignore "
788 "the nodes in the simulation zone");
791 const bNode *node =
b.node_or_null();
792 if (node ==
nullptr) {
806 auto &input_decl =
b.add_input(socket_type, name, identifier)
809 auto &output_decl =
b.add_output(socket_type, name, identifier).align_with_previous();
812 input_decl.supports_field().structure_type(StructureType::Dynamic);
813 output_decl.dependent_field({input_decl.index()});
816 b.add_input<
decl::Extend>(
"",
"__extend__").structure_type(StructureType::Dynamic);
818 .structure_type(StructureType::Dynamic)
819 .align_with_previous();
826 data->next_identifier = 0;
831 data->items[0].identifier =
data->next_identifier++;
847 dst_node->
storage = dst_storage;
860 *ntree, *node, *node, *link);
871 row.
text =
TIP_(
"Can't bake in zone");
872 row.
icon = ICON_ERROR;
873 params.rows.append(std::move(row));
878 params.rows.append(std::move(row));
889 bNode &input_node =
params.add_node(
"GeometryNodeSimulationInput");
890 bNode &output_node =
params.add_node(
"GeometryNodeSimulationOutput");
902 params.connect_available_socket(output_node,
params.socket.name);
905 params.connect_available_socket(input_node,
params.socket.name);
907 params.node_tree.ensure_topology_cache();
910 input_node.output_socket(1),
912 output_node.input_socket(1));
931 ntype.
ui_name =
"Simulation Output";
964 return std::make_unique<
966 node_tree, node, own_lf_graph_info);
973 return std::make_unique<
975 node, own_lf_graph_info);
983 switch (socket_type) {
1007 prev_value_variant.convert_to_single();
1008 next_value_variant.convert_to_single();
1014 using T =
decltype(dummy);
1016 factor, *
static_cast<T *
>(prev_value), *
static_cast<const T *
>(next_value));
Low-level operations for curves.
#define NODE_CLASS_INTERFACE
#define NODE_STORAGE_FUNCS(StorageT)
#define GEO_NODE_SIMULATION_OUTPUT
#define GEO_NODE_SIMULATION_INPUT
#define BLI_assert_unreachable()
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
char * BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define NOD_REGISTER_NODE(REGISTER_FUNC)
void uiLayoutSetActive(uiLayout *layout, bool active)
void uiLayoutSetEnabled(uiLayout *layout, bool enabled)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
BMesh const char void * data
void resize(const int64_t new_size)
Span< T > as_span() const
static const CPPType & get()
void destruct(void *ptr) const
const ComputeContextHash & hash() const
void * allocate(const int64_t size, const int64_t alignment)
constexpr int64_t size() const
constexpr IndexRange index_range() const
void append(const T &value)
void resize(const int64_t new_size)
bool is_context_dependent_field() const
GPointer get_single_ptr() const
std::optional< int > output_node_id
const bNode * output_node() const
const bNodeTreeZone * get_zone_by_node(const int32_t node_id) const
Vector< Output > outputs_
Span< Output > outputs() const
virtual SimulationZoneBehavior * get(const int zone_id) const =0
void output_mixed_cached_state(lf::Params ¶ms, bke::bake::BakeDataBlockMap *data_block_map, const Object &self_object, const ComputeContext &compute_context, const bke::bake::BakeStateRef &prev_state, const bke::bake::BakeStateRef &next_state, const float mix_factor) const
void pass_through(lf::Params ¶ms, GeoNodesUserData &user_data, bke::bake::BakeDataBlockMap *data_block_map) const
void execute_impl(lf::Params ¶ms, const lf::Context &context) const final
void store_new_state(lf::Params ¶ms, GeoNodesUserData &user_data, bke::bake::BakeDataBlockMap *data_block_map, const sim_output::StoreNewState &info) const
LazyFunctionForSimulationOutputNode(const bNode &node, GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
void set_default_outputs(lf::Params ¶ms) const
void output_cached_state(lf::Params ¶ms, GeoNodesUserData &user_data, bke::bake::BakeDataBlockMap *data_block_map, const bke::bake::BakeStateRef &state) const
std::optional< bke::bake::BakeState > get_bake_state_from_inputs(lf::Params ¶ms, bke::bake::BakeDataBlockMap *data_block_map, const bool skip) const
#define ID_IS_EDITABLE(_id)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
void * MEM_callocN(size_t len, const char *str)
void * MEM_dupallocN(const void *vmemh)
void MEM_freeN(void *vmemh)
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
T mix2(float factor, const T &a, const T &b)
Array< std::unique_ptr< BakeItem > > move_socket_values_to_bake_items(Span< void * > socket_values, const BakeSocketConfig &config, BakeDataBlockMap *data_block_map)
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)
void node_register_type(bNodeType &ntype)
const CPPType * socket_type_to_geo_nodes_base_cpp_type(eNodeSocketDatatype type)
bNodeLink & node_add_link(bNodeTree &ntree, bNode &fromnode, bNodeSocket &fromsock, bNode &tonode, bNodeSocket &tosock)
bNodeSocketType * node_socket_type_find_static(int type, int subtype=0)
std::string hash_to_anonymous_attribute_name(Args &&...args)
void node_type_storage(bNodeType &ntype, std::optional< StringRefNull > storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
bke::GeometrySet mix_geometries(bke::GeometrySet a, const bke::GeometrySet &b, float factor)
static void node_blend_write(const bNodeTree &, const bNode &node, BlendWriter &writer)
static void node_copy_storage(bNodeTree *, bNode *dst_node, const bNode *src_node)
static void node_declare(NodeDeclarationBuilder &b)
static void node_extra_info(NodeExtraInfoParams ¶ms)
static void node_operators()
static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
static void node_init(bNodeTree *, bNode *node)
static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms)
static void node_blend_read(bNodeTree &, bNode &node, BlendDataReader &reader)
static void node_free_storage(bNode *node)
static void node_register()
static const CPPType & get_simulation_item_cpp_type(const eNodeSocketDatatype socket_type)
static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *current_node_ptr)
static bke::bake::BakeState move_values_to_simulation_state(const Span< NodeSimulationItem > node_simulation_items, const Span< void * > input_values, bke::bake::BakeDataBlockMap *data_block_map)
static std::shared_ptr< AttributeFieldInput > make_attribute_field(const Object &self_object, const ComputeContext &compute_context, const bNode &node, const NodeSimulationItem &item, const CPPType &type)
static void move_simulation_state_to_values(const Span< NodeSimulationItem > node_simulation_items, bke::bake::BakeState zone_state, const Object &self_object, const ComputeContext &compute_context, const bNode &node, bke::bake::BakeDataBlockMap *data_block_map, Span< void * > r_output_values)
static void draw_simulation_state(const bContext *C, uiLayout *layout, bNodeTree &ntree, bNode &output_node)
static bke::bake::BakeSocketConfig make_bake_socket_config(const Span< NodeSimulationItem > node_simulation_items)
static void copy_simulation_state_to_values(const Span< NodeSimulationItem > node_simulation_items, const bke::bake::BakeStateRef &zone_state, const Object &self_object, const ComputeContext &compute_context, const bNode &node, bke::bake::BakeDataBlockMap *data_block_map, Span< void * > r_output_values)
std::variant< PassThrough, StoreNewState, ReadSingle, ReadInterpolated, ReadError > Behavior
void make_common_operators()
static void draw_items_list_with_operators(const bContext *C, uiLayout *layout, const bNodeTree &tree, const bNode &node)
static void draw_active_item_props(const bNodeTree &tree, const bNode &node, const FunctionRef< void(PointerRNA *item_ptr)> draw_item)
void blend_write(BlendWriter *writer, const bNode &node)
void destruct_array(bNode &node)
void blend_read_data(BlendDataReader *reader, bNode &node)
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)
std::unique_ptr< LazyFunction > get_simulation_output_lazy_function(const bNode &node, GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
void draw_data_blocks(const bContext *C, uiLayout *layout, PointerRNA &bake_rna)
std::unique_ptr< LazyFunction > get_simulation_input_lazy_function(const bNodeTree &node_tree, const bNode &node, GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
void update_node_declaration_and_sockets(bNodeTree &ntree, bNode &node)
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::optional< FoundNestedNodeID > find_nested_node_id(const GeoNodesUserData &user_data, const int node_id)
bool socket_type_supports_fields(const eNodeSocketDatatype socket_type)
void set_default_remaining_node_outputs(lf::Params ¶ms, const bNode &node)
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)
void geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
void node_free_standard_storage(bNode *node)
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
NodeSimulationItem * items
bNodeSocketTypeHandle * typeinfo
const blender::CPPType * geometry_nodes_cpp_type
NodeBlendWriteFunction blend_write_storage_content
std::string ui_description
NodeBlendDataReadFunction blend_data_read_storage_content
void(* initfunc)(bNodeTree *ntree, bNode *node)
void(* labelfunc)(const bNodeTree *ntree, const bNode *node, char *label, int label_maxncpy)
void(* draw_buttons_ex)(uiLayout *, bContext *C, PointerRNA *ptr)
NodeExtraInfoFunction get_extra_info
const char * enum_name_legacy
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
bool(* insert_link)(bNodeTree *ntree, bNode *node, bNodeLink *link)
NodeDeclareFunction declare
void(* register_operators)()
Vector< Vector< int, 1 > > geometries_by_attribute
Vector< StringRef > names
Vector< eNodeSocketDatatype > types
Vector< AttrDomain > domains
Map< int, const BakeItem * > items_by_id
Map< int, std::unique_ptr< BakeItem > > items_by_id
bool is_bakeable_in_current_context
GeoNodesSimulationParams * simulation_params
const Object * self_object() const
geo_eval_log::GeoTreeLogger * try_get_tree_logger(const GeoNodesUserData &user_data) const
const ComputeContext * compute_context
const GeoNodesCallData * call_data
Array< int > lf_index_by_bsocket
GeometryNodeLazyFunctionGraphMapping mapping
static void blend_read_data_item(BlendDataReader *reader, ItemT &item)
static std::string socket_identifier_for_item(const NodeSimulationItem &item)
static void blend_write_item(BlendWriter *writer, const ItemT &item)
static StructRNA * item_srna
static bool supports_socket_type(const eNodeSocketDatatype socket_type)
bke::bake::BakeDataBlockMap * data_block_map
sim_input::Behavior input
std::function< void(bke::bake::BakeState state)> store_fn
PanelLayout panel(const bContext *C, blender::StringRef idname, bool default_closed)
void label(blender::StringRef name, int icon)
uiLayout & column(bool align)