49#include "RNA_prototypes.hh"
83 const int items_num = node_simulation_items.
size();
89 int last_geometry_index = -1;
90 for (
const int item_i : node_simulation_items.
index_range()) {
96 last_geometry_index = item_i;
98 else if (last_geometry_index != -1) {
106 const Object &self_object,
115 node.label_or_name(), item.
name);
116 return std::make_shared<AttributeFieldInput>(
117 std::move(attribute_name), type, std::move(socket_inspection_name));
122 const Object &self_object,
131 std::unique_ptr<bke::bake::BakeItem> *bake_item = zone_state.
items_by_id.lookup_ptr(
133 bake_items.
append(bake_item ? bake_item->get() :
nullptr);
140 [&](
const int i,
const CPPType &type) {
142 self_object, compute_context, node, node_simulation_items[i], type);
149 const Object &self_object,
160 bake_items.
append(bake_item ? *bake_item :
nullptr);
167 [&](
const int i,
const CPPType &type) {
169 self_object, compute_context, node, node_simulation_items[i], type);
185 for (
const int i : node_simulation_items.
index_range()) {
187 std::unique_ptr<bke::bake::BakeItem> &bake_item = bake_items[i];
219 static const uiListType *state_items_list = []() {
220 uiListType *list = MEM_cnew<uiListType>(__func__);
221 STRNCPY(list->idname,
"DATA_UL_simulation_zone_state");
230 C, layout,
"simulation_state_items",
false,
TIP_(
"Simulation State")))
252 uiItemO(add_remove_col,
"", ICON_ADD,
"node.simulation_zone_item_add");
253 uiItemO(add_remove_col,
"", ICON_REMOVE,
"node.simulation_zone_item_remove");
258 up_down_col,
"node.simulation_zone_item_move",
"", ICON_TRIA_UP,
"direction", 0);
260 up_down_col,
"node.simulation_zone_item_move",
"", ICON_TRIA_DOWN,
"direction", 1);
265 if (storage.active_index >= 0 && storage.active_index < storage.items_num) {
282 ot,
"Remove Simulation Zone Item", __func__,
"Remove active simulation zone item");
288 ot,
"Add Simulation Zone Item", __func__,
"Add simulation zone item");
294 ot,
"Move Simulation Zone Item", __func__,
"Move active simulation zone item");
301 bNode *current_node =
static_cast<bNode *
>(current_node_ptr->
data);
311 if (!zone->output_node) {
314 bNode &output_node =
const_cast<bNode &
>(*zone->output_node);
333 uiItemL(row, bake_state_str->c_str(), ICON_NONE);
340namespace sim_input_node {
356 output_node_id_ = node_storage(node).output_node_id;
357 const bNode &output_node = *
node_tree.node_by_id(output_node_id_);
363 lf_index_by_bsocket[node.output_socket(0).index_in_tree()] =
outputs_.append_and_get_index_as(
366 for (
const int i : simulation_items_.
index_range()) {
368 const bNodeSocket &input_bsocket = node.input_socket(i);
369 const bNodeSocket &output_bsocket = node.output_socket(i + 1);
373 lf_index_by_bsocket[input_bsocket.index_in_tree()] =
inputs_.append_and_get_index_as(
374 item.
name, type, lf::ValueUsage::Maybe);
375 lf_index_by_bsocket[output_bsocket.index_in_tree()] =
outputs_.append_and_get_index_as(
393 std::optional<FoundNestedNodeID> found_id =
find_nested_node_id(user_data, output_node_id_);
398 if (found_id->is_in_loop) {
404 if (!zone_behavior) {
409 float delta_time = 0.0f;
410 if (
auto *info = std::get_if<sim_input::OutputCopy>(&input_behavior)) {
411 delta_time = info->delta_time;
415 else if (
auto *info = std::get_if<sim_input::OutputMove>(&input_behavior)) {
416 delta_time = info->delta_time;
420 else if (std::get_if<sim_input::PassThrough>(&input_behavior)) {
427 if (!
params.output_was_set(0)) {
443 for (
const int i : simulation_items_.
index_range()) {
444 outputs[i] =
params.get_output_data_ptr(i + 1);
453 for (
const int i : simulation_items_.
index_range()) {
464 for (
const int i : simulation_items_.
index_range()) {
465 outputs[i] =
params.get_output_data_ptr(i + 1);
468 std::move(zone_state),
474 for (
const int i : simulation_items_.
index_range()) {
484 for (
const int i :
inputs_.index_range()) {
485 input_values[i] =
params.try_get_input_data_ptr_or_request(i);
487 if (input_values.
as_span().contains(
nullptr)) {
495 simulation_items_, input_values, data_block_map);
502 b.use_custom_socket_order();
503 b.allow_any_socket_order();
506 const bNode *node =
b.node_or_null();
512 const bNode *output_node =
node_tree->node_by_id(node_storage(*node).output_node_id);
519 for (
const int i :
IndexRange(output_storage.items_num)) {
527 auto &input_decl =
b.add_input(socket_type, name, identifier)
530 auto &output_decl =
b.add_output(socket_type, name, identifier).align_with_previous();
532 input_decl.supports_field();
533 output_decl.dependent_field({input_decl.index()});
537 b.add_output<
decl::Extend>(
"",
"__extend__").align_with_previous();
544 data->output_node_id = 0;
545 node->storage =
data;
551 const int label_maxncpy)
558 bNode *output_node = ntree->node_by_id(node_storage(*node).output_node_id);
563 *ntree, *node, *output_node, *link);
578 "NodeGeometrySimulationInput",
587namespace sim_output_node {
594 int skip_input_index_;
600 int skip_inputs_offset_;
605 int solve_inputs_offset_;
618 const bNodeSocket &skip_bsocket = node.input_socket(0);
619 skip_input_index_ =
inputs_.append_and_get_index_as(
620 "Skip", *skip_bsocket.
typeinfo->geometry_nodes_cpp_type, lf::ValueUsage::Maybe);
621 lf_index_by_bsocket[skip_bsocket.index_in_tree()] = skip_input_index_;
626 for (
const int i : simulation_items_.
index_range()) {
629 inputs_.append_as(item.
name, type, lf::ValueUsage::Maybe);
632 solve_inputs_offset_ =
inputs_.size();
635 for (
const int i : simulation_items_.
index_range()) {
637 const bNodeSocket &input_bsocket = node.input_socket(i + 1);
638 const bNodeSocket &output_bsocket = node.output_socket(i);
642 lf_index_by_bsocket[input_bsocket.index_in_tree()] =
inputs_.append_and_get_index_as(
643 item.
name, type, lf::ValueUsage::Maybe);
644 lf_index_by_bsocket[output_bsocket.index_in_tree()] =
outputs_.append_and_get_index_as(
661 std::optional<FoundNestedNodeID> found_id =
find_nested_node_id(user_data, node_.identifier);
666 if (found_id->is_in_loop) {
672 if (!zone_behavior) {
677 if (
auto *info = std::get_if<sim_output::ReadSingle>(&output_behavior)) {
680 else if (
auto *info = std::get_if<sim_output::ReadInterpolated>(&output_behavior)) {
689 else if (std::get_if<sim_output::PassThrough>(&output_behavior)) {
692 else if (
auto *info = std::get_if<sim_output::StoreNewState>(&output_behavior)) {
711 for (
const int i : simulation_items_.
index_range()) {
712 output_values[i] =
params.get_output_data_ptr(i);
721 for (
const int i : simulation_items_.
index_range()) {
728 const Object &self_object,
732 const float mix_factor)
const
735 for (
const int i : simulation_items_.
index_range()) {
736 output_values[i] =
params.get_output_data_ptr(i);
748 for (
const int i : simulation_items_.
index_range()) {
750 next_values[i] = allocator.
allocate(type.size(), type.alignment());
760 for (
const int i : simulation_items_.
index_range()) {
767 for (
const int i : simulation_items_.
index_range()) {
772 for (
const int i : simulation_items_.
index_range()) {
782 params, data_block_map,
true);
789 for (
const int i : simulation_items_.
index_range()) {
790 output_values[i] =
params.get_output_data_ptr(i);
793 std::move(*bake_state),
799 for (
const int i : simulation_items_.
index_range()) {
811 if (skip_variant ==
nullptr) {
815 const bool skip = skip_variant->
get<
bool>();
821 params, data_block_map, skip);
827 info.
store_fn(std::move(*bake_state));
834 const int params_offset = skip ? skip_inputs_offset_ : solve_inputs_offset_;
836 for (
const int i : simulation_items_.
index_range()) {
837 input_values[i] =
params.try_get_input_data_ptr_or_request(i + params_offset);
839 if (input_values.
as_span().contains(
nullptr)) {
850 b.use_custom_socket_order();
851 b.allow_any_socket_order();
853 "Forward the output of the simulation input node directly to the output node and ignore "
854 "the nodes in the simulation zone");
857 const bNode *node =
b.node_or_null();
858 if (node ==
nullptr) {
872 auto &input_decl =
b.add_input(socket_type, name, identifier)
875 auto &output_decl =
b.add_output(socket_type, name, identifier).align_with_previous();
877 input_decl.supports_field();
878 output_decl.dependent_field({input_decl.index()});
882 b.add_output<
decl::Extend>(
"",
"__extend__").align_with_previous();
889 data->next_identifier = 0;
891 data->items = MEM_cnew_array<NodeSimulationItem>(1, __func__);
894 data->items[0].identifier = data->next_identifier++;
897 node->storage =
data;
909 auto *dst_storage = MEM_cnew<NodeGeometrySimulationOutput>(__func__, src_storage);
910 dst_node->
storage = dst_storage;
925 *ntree, *node, *node, *link);
937 params.rows.append(std::move(row));
973 BLI_assert(node.type == GEO_NODE_SIMULATION_INPUT);
974 return std::make_unique<
982 BLI_assert(node.type == GEO_NODE_SIMULATION_OUTPUT);
983 return std::make_unique<
985 node, own_lf_graph_info);
993 switch (socket_type) {
1024 using T =
decltype(dummy);
1026 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
General operations, lookup, etc. for blender objects.
#define BLI_assert_unreachable()
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
#define STRNCPY(dst, src)
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 BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
#define ID_IS_EDITABLE(_id)
#define NOD_REGISTER_NODE(REGISTER_FUNC)
void uiLayoutSetEnabled(uiLayout *layout, bool enabled)
void uiItemL(uiLayout *layout, const char *name, int icon)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
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)
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)
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 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
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 pass_through(lf::Params ¶ms, GeoNodesLFUserData &user_data, bke::bake::BakeDataBlockMap *data_block_map) const
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 store_new_state(lf::Params ¶ms, GeoNodesLFUserData &user_data, bke::bake::BakeDataBlockMap *data_block_map, const sim_output::StoreNewState &info) const
void execute_impl(lf::Params ¶ms, const lf::Context &context) const final
LazyFunctionForSimulationOutputNode(const bNode &node, GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
void set_default_outputs(lf::Params ¶ms) const
void output_cached_state(lf::Params ¶ms, GeoNodesLFUserData &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
local_group_size(16, 16) .push_constant(Type b
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)
bNodeSocketType * node_socket_type_find(const char *idname)
const char * node_static_socket_type(int type, int subtype)
const CPPType * socket_type_to_geo_nodes_base_cpp_type(eNodeSocketDatatype type)
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))
void node_register_type(bNodeType *ntype)
std::string hash_to_anonymous_attribute_name(Args &&...args)
bke::GeometrySet mix_geometries(bke::GeometrySet a, const bke::GeometrySet &b, float factor)
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_free_storage(bNode *node)
static void node_register()
static const CPPType & get_simulation_item_cpp_type(const eNodeSocketDatatype socket_type)
static void NODE_OT_simulation_zone_item_add(wmOperatorType *ot)
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 void NODE_OT_simulation_zone_item_move(wmOperatorType *ot)
static void NODE_OT_simulation_zone_item_remove(wmOperatorType *ot)
static void draw_simulation_state_item(uiList *, const bContext *C, uiLayout *layout, PointerRNA *, PointerRNA *itemptr, int, PointerRNA *, const char *, int, int)
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 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 destruct_array(bNode &node)
void copy_array(const bNode &src_node, bNode &dst_node)
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 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)
bool socket_type_supports_fields(const eNodeSocketDatatype socket_type)
void set_default_remaining_node_outputs(lf::Params ¶ms, 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)
void geo_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
void node_free_standard_storage(bNode *node)
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
NodeSimulationItem * items
bNodeSocketTypeHandle * typeinfo
const blender::CPPType * geometry_nodes_cpp_type
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
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
GeoNodesSimulationParams * simulation_params
const Object * self_object() const
const ComputeContext * compute_context
const GeoNodesCallData * call_data
Array< int > lf_index_by_bsocket
GeometryNodeLazyFunctionGraphMapping mapping
static void blend_write(BlendWriter *writer, const bNode &node)
static std::string socket_identifier_for_item(const NodeSimulationItem &item)
static StructRNA * item_srna
static void blend_read_data(BlendDataReader *reader, bNode &node)
sim_output::Behavior output
bke::bake::BakeDataBlockMap * data_block_map
sim_input::Behavior input
std::function< void(bke::bake::BakeState state)> store_fn
char idname[BKE_ST_MAXNAME]
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))
bool WM_uilisttype_add(uiListType *ult)