WIP: Geometry Nodes: new Bake node #110137
@ -478,6 +478,92 @@ class RepeatZoneItemMoveOperator(RepeatZoneOperator, Operator):
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class BakeNodeOperator:
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
space = context.space_data
|
||||
if not space or space.type != 'NODE_EDITOR' or not space.edit_tree or space.edit_tree.library:
|
||||
return False
|
||||
node = context.active_node
|
||||
if node is None:
|
||||
return False
|
||||
if node.bl_idname != "GeometryNodeBake":
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class BakeItemAddOperator(BakeNodeOperator, Operator):
|
||||
"""Add a bake item to the bake node"""
|
||||
bl_idname = "node.bake_item_add"
|
||||
bl_label = "Add Bake Item"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
default_socket_type = 'GEOMETRY'
|
||||
|
||||
def execute(self, context):
|
||||
node = context.active_node
|
||||
bake_items = node.bake_items
|
||||
|
||||
# Remember index to move the item.
|
||||
if node.active_item:
|
||||
dst_index = node.active_index + 1
|
||||
dst_type = node.active_item.socket_type
|
||||
dst_name = node.active_item.name
|
||||
else:
|
||||
dst_index = len(bake_items)
|
||||
dst_type = self.default_socket_type
|
||||
# Empty name so it is based on the type.
|
||||
dst_name = ""
|
||||
bake_items.new(dst_type, dst_name)
|
||||
bake_items.move(len(bake_items) - 1, dst_index)
|
||||
node.active_index = dst_index
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class BakeItemRemoveOperator(BakeNodeOperator, Operator):
|
||||
"""Remove a bake item from the bake node"""
|
||||
bl_idname = "node.bake_item_remove"
|
||||
bl_label = "Remove Bake Item"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
def execute(self, context):
|
||||
node = context.active_node
|
||||
bake_items = node.bake_items
|
||||
|
||||
if node.active_item:
|
||||
bake_items.remove(node.active_item)
|
||||
node.active_index = min(node.active_index, len(bake_items) - 1)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class BakeItemMoveOperator(BakeNodeOperator, Operator):
|
||||
"""Move a bake item up or down in the list"""
|
||||
bl_idname = "node.bake_item_move"
|
||||
bl_label = "Move Bake Item"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
direction: EnumProperty(
|
||||
name="Direction",
|
||||
items=[('UP', "Up", ""), ('DOWN', "Down", "")],
|
||||
default='UP',
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
node = context.active_node
|
||||
bake_items = node.bake_items
|
||||
|
||||
if self.direction == 'UP' and node.active_index > 0:
|
||||
bake_items.move(node.active_index, node.active_index - 1)
|
||||
node.active_index = node.active_index - 1
|
||||
elif self.direction == 'DOWN' and node.active_index < len(bake_items) - 1:
|
||||
bake_items.move(node.active_index, node.active_index + 1)
|
||||
node.active_index = node.active_index + 1
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
classes = (
|
||||
NewGeometryNodesModifier,
|
||||
NewGeometryNodeTreeAssign,
|
||||
@ -489,4 +575,7 @@ classes = (
|
||||
RepeatZoneItemAddOperator,
|
||||
RepeatZoneItemRemoveOperator,
|
||||
RepeatZoneItemMoveOperator,
|
||||
BakeItemAddOperator,
|
||||
BakeItemRemoveOperator,
|
||||
BakeItemMoveOperator,
|
||||
)
|
||||
|
@ -167,6 +167,7 @@ class NODE_MT_geometry_node_GEO_GEOMETRY(Menu):
|
||||
layout.separator()
|
||||
layout.menu("NODE_MT_geometry_node_GEO_GEOMETRY_OPERATIONS")
|
||||
layout.separator()
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeBake")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeGeometryToInstance")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeJoinGeometry")
|
||||
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
|
||||
|
@ -1312,6 +1312,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
|
||||
#define GEO_NODE_TOOL_FACE_SET 2112
|
||||
#define GEO_NODE_TOOL_SET_FACE_SET 2113
|
||||
#define GEO_NODE_POINTS_TO_CURVES 2114
|
||||
#define GEO_NODE_BAKE 2115
|
||||
|
||||
/** \} */
|
||||
|
||||
|
@ -797,6 +797,13 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
|
||||
BLO_write_string(writer, item.name);
|
||||
}
|
||||
}
|
||||
if (node->type == GEO_NODE_BAKE) {
|
||||
const NodeGeometryBake &storage = *static_cast<const NodeGeometryBake *>(node->storage);
|
||||
BLO_write_struct_array(writer, NodeGeometryBakeItem, storage.items_num, storage.items);
|
||||
for (const NodeGeometryBakeItem &item : storage.items_span()) {
|
||||
BLO_write_string(writer, item.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
|
||||
@ -1004,6 +1011,14 @@ void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GEO_NODE_BAKE: {
|
||||
NodeGeometryBake &storage = *static_cast<NodeGeometryBake *>(node->storage);
|
||||
BLO_read_data_address(reader, &storage.items);
|
||||
for (const NodeGeometryBakeItem &item : storage.items_span()) {
|
||||
BLO_read_data_address(reader, &item.name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
|
@ -632,3 +632,24 @@ bool bNodeTree::node_id_path_from_nested_node_ref(const int32_t nested_node_id,
|
||||
}
|
||||
return group->node_id_path_from_nested_node_ref(ref->path.id_in_node, r_node_ids);
|
||||
}
|
||||
|
||||
const bNode *bNodeTree::find_nested_node(const int32_t nested_node_id) const
|
||||
{
|
||||
const bNestedNodeRef *ref = this->find_nested_node_ref(nested_node_id);
|
||||
if (ref == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
const int32_t node_id = ref->path.node_id;
|
||||
const bNode *node = this->node_by_id(node_id);
|
||||
if (node == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!node->is_group()) {
|
||||
return node;
|
||||
}
|
||||
const bNodeTree *group = reinterpret_cast<const bNodeTree *>(node->id);
|
||||
if (group == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return group->find_nested_node(ref->path.id_in_node);
|
||||
}
|
||||
|
@ -1131,10 +1131,10 @@ class NodeTreeMainUpdater {
|
||||
|
||||
/* Simplify lookup of old ids. */
|
||||
Map<bNestedNodePath, int32_t> old_id_by_path;
|
||||
Set<int32_t> old_ids;
|
||||
VectorSet<int32_t> sorted_old_ids;
|
||||
for (const bNestedNodeRef &ref : ntree.nested_node_refs_span()) {
|
||||
old_id_by_path.add(ref.path, ref.id);
|
||||
old_ids.add(ref.id);
|
||||
sorted_old_ids.add(ref.id);
|
||||
}
|
||||
|
||||
Vector<bNestedNodePath> nested_node_paths;
|
||||
@ -1153,6 +1153,10 @@ class NodeTreeMainUpdater {
|
||||
for (const bNode *node : ntree.nodes_by_type("GeometryNodeSimulationOutput")) {
|
||||
nested_node_paths.append({node->identifier, -1});
|
||||
}
|
||||
/* Create references for bake nodes. */
|
||||
for (const bNode *node : ntree.nodes_by_type("GeometryNodeBake")) {
|
||||
nested_node_paths.append({node->identifier, -1});
|
||||
}
|
||||
}
|
||||
/* Propagate references to nested nodes in group nodes. */
|
||||
for (const bNode *node : ntree.group_nodes()) {
|
||||
@ -1180,7 +1184,7 @@ class NodeTreeMainUpdater {
|
||||
int32_t new_id;
|
||||
while (true) {
|
||||
new_id = rng.get_int32(INT32_MAX);
|
||||
if (!old_ids.contains(new_id) && !new_path_by_id.contains(new_id)) {
|
||||
if (!sorted_old_ids.contains(new_id) && !new_path_by_id.contains(new_id)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1210,6 +1214,21 @@ class NodeTreeMainUpdater {
|
||||
index++;
|
||||
}
|
||||
|
||||
/* Keep references in the same order as before and only add new references at the end. */
|
||||
std::sort(new_refs,
|
||||
new_refs + new_path_by_id.size(),
|
||||
[&](const bNestedNodeRef &a, const bNestedNodeRef &b) {
|
||||
int a_index = sorted_old_ids.index_of_try(a.id);
|
||||
int b_index = sorted_old_ids.index_of_try(b.id);
|
||||
if (a_index == -1) {
|
||||
a_index = INT32_MAX;
|
||||
}
|
||||
if (b_index == -1) {
|
||||
b_index = INT32_MAX;
|
||||
}
|
||||
return a_index < b_index;
|
||||
});
|
||||
|
||||
ntree.nested_node_refs = new_refs;
|
||||
ntree.nested_node_refs_num = new_path_by_id.size();
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "BLI_vector_set.hh"
|
||||
#include "ED_node_c.hh"
|
||||
|
||||
@ -33,4 +35,9 @@ void node_insert_on_link_flags_clear(bNodeTree &node_tree);
|
||||
*/
|
||||
void node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[4], float scale);
|
||||
|
||||
/**
|
||||
* Find the nested node id of a currently visible node in the root tree.
|
||||
*/
|
||||
std::optional<int32_t> find_nested_node_id_in_root(const SpaceNode &snode, const bNode &node);
|
||||
|
||||
} // namespace blender::ed::space_node
|
||||
|
@ -33,6 +33,7 @@ set(SRC
|
||||
object_add.cc
|
||||
object_bake.cc
|
||||
object_bake_api.cc
|
||||
object_bake_geometry_nodes.cc
|
||||
object_bake_simulation.cc
|
||||
object_collection.cc
|
||||
object_constraint.cc
|
||||
|
156
source/blender/editors/object/object_bake_geometry_nodes.cc
Normal file
156
source/blender/editors/object/object_bake_geometry_nodes.cc
Normal file
@ -0,0 +1,156 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "ED_object.hh"
|
||||
#include "ED_screen.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_define.hh"
|
||||
|
||||
#include "DNA_modifier_types.h"
|
||||
|
||||
#include "MOD_nodes.hh"
|
||||
|
||||
#include "BKE_bake_items_serialize.hh"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_scene.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
|
||||
#include "BLI_fileops.hh"
|
||||
#include "BLI_path_util.h"
|
||||
#include "BLI_string_utils.h"
|
||||
|
||||
#include "object_intern.h"
|
||||
|
||||
namespace blender::ed::object::bake_geometry_nodes {
|
||||
|
||||
static void bake_operator_props(wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
WM_operator_properties_id_lookup(ot, false);
|
||||
|
||||
prop = RNA_def_string(
|
||||
ot->srna, "modifier", nullptr, MAX_NAME, "Modifier", "Name of the modifier");
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
|
||||
prop = RNA_def_int(ot->srna, "bake_id", 0, 0, INT32_MAX, "Bake ID", "", 0, INT32_MAX);
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool find_edit_bake(Main *bmain,
|
||||
wmOperator *op,
|
||||
Object **r_object,
|
||||
NodesModifierData **r_modifier,
|
||||
NodesModifierBake **r_bake)
|
||||
{
|
||||
Object *object = reinterpret_cast<Object *>(
|
||||
WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_OB));
|
||||
if (object == nullptr) {
|
||||
return false;
|
||||
}
|
||||
char modifier_name[MAX_NAME];
|
||||
RNA_string_get(op->ptr, "modifier", modifier_name);
|
||||
ModifierData *md = BKE_modifiers_findby_name(object, modifier_name);
|
||||
if (md == nullptr || md->type != eModifierType_Nodes) {
|
||||
return false;
|
||||
}
|
||||
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
|
||||
const int bake_id = RNA_int_get(op->ptr, "bake_id");
|
||||
NodesModifierBake *bake = nullptr;
|
||||
for (NodesModifierBake &bake_iter : MutableSpan(nmd->bakes, nmd->bakes_num)) {
|
||||
if (bake_iter.id == bake_id) {
|
||||
bake = &bake_iter;
|
||||
}
|
||||
}
|
||||
if (bake == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*r_object = object;
|
||||
*r_modifier = nmd;
|
||||
*r_bake = bake;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int geometry_node_bake_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
|
||||
Object *object;
|
||||
NodesModifierData *modifier;
|
||||
NodesModifierBake *bake;
|
||||
if (!find_edit_bake(bmain, op, &object, &modifier, &bake)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
NodesModifierData &nmd = *modifier;
|
||||
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
||||
|
||||
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, nullptr);
|
||||
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
static int geometry_node_bake_delete_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
||||
Object *object;
|
||||
NodesModifierData *modifier;
|
||||
NodesModifierBake *bake;
|
||||
if (!find_edit_bake(bmain, op, &object, &modifier, &bake)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
NodesModifierData &nmd = *modifier;
|
||||
|
||||
DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
|
||||
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, nullptr);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static int geometry_node_bake_delete_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
|
||||
{
|
||||
if (edit_modifier_invoke_properties(C, op)) {
|
||||
return geometry_node_bake_delete_exec(C, op);
|
||||
}
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
} // namespace blender::ed::object::bake_geometry_nodes
|
||||
|
||||
void OBJECT_OT_geometry_node_bake(wmOperatorType *ot)
|
||||
{
|
||||
using namespace blender::ed::object::bake_geometry_nodes;
|
||||
|
||||
ot->name = "Bake Geometry Node";
|
||||
ot->description = "Bake geometry in a Bake node in geometry nodes";
|
||||
ot->idname = __func__;
|
||||
|
||||
ot->exec = geometry_node_bake_exec;
|
||||
ot->poll = ED_operator_object_active_editable;
|
||||
|
||||
bake_operator_props(ot);
|
||||
}
|
||||
|
||||
void OBJECT_OT_geometry_node_bake_delete(wmOperatorType *ot)
|
||||
{
|
||||
using namespace blender::ed::object::bake_geometry_nodes;
|
||||
|
||||
ot->name = "Delete Geometry Node Bake";
|
||||
ot->description = "Delete baked data";
|
||||
ot->idname = __func__;
|
||||
|
||||
ot->invoke = geometry_node_bake_delete_invoke;
|
||||
ot->exec = geometry_node_bake_delete_exec;
|
||||
ot->poll = ED_operator_object_active_editable;
|
||||
|
||||
bake_operator_props(ot);
|
||||
}
|
@ -348,6 +348,11 @@ void OBJECT_OT_simulation_nodes_cache_calculate_to_frame(wmOperatorType *ot);
|
||||
void OBJECT_OT_simulation_nodes_cache_bake(wmOperatorType *ot);
|
||||
void OBJECT_OT_simulation_nodes_cache_delete(wmOperatorType *ot);
|
||||
|
||||
/* object_bake_geometry_nodes.cc */
|
||||
|
||||
void OBJECT_OT_geometry_node_bake(wmOperatorType *ot);
|
||||
void OBJECT_OT_geometry_node_bake_delete(wmOperatorType *ot);
|
||||
|
||||
/* `object_random.cc` */
|
||||
|
||||
void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot);
|
||||
|
@ -257,6 +257,8 @@ void ED_operatortypes_object()
|
||||
WM_operatortype_append(OBJECT_OT_simulation_nodes_cache_calculate_to_frame);
|
||||
WM_operatortype_append(OBJECT_OT_simulation_nodes_cache_bake);
|
||||
WM_operatortype_append(OBJECT_OT_simulation_nodes_cache_delete);
|
||||
WM_operatortype_append(OBJECT_OT_geometry_node_bake);
|
||||
WM_operatortype_append(OBJECT_OT_geometry_node_bake_delete);
|
||||
WM_operatortype_append(OBJECT_OT_drop_named_material);
|
||||
WM_operatortype_append(OBJECT_OT_drop_geometry_nodes);
|
||||
WM_operatortype_append(OBJECT_OT_unlink_data);
|
||||
|
@ -237,6 +237,52 @@ float2 space_node_group_offset(const SpaceNode &snode)
|
||||
return float2(0);
|
||||
}
|
||||
|
||||
static const bNode *group_node_by_name(const bNodeTree &ntree, StringRef name)
|
||||
{
|
||||
for (const bNode *node : ntree.group_nodes()) {
|
||||
if (node->name == name) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::optional<int32_t> find_nested_node_id_in_root(const SpaceNode &snode, const bNode &query_node)
|
||||
{
|
||||
BLI_assert(snode.edittree->runtime->nodes_by_id.contains(const_cast<bNode *>(&query_node)));
|
||||
|
||||
std::optional<int32_t> id_in_node;
|
||||
const char *group_node_name = nullptr;
|
||||
const bNode *node = &query_node;
|
||||
LISTBASE_FOREACH_BACKWARD (const bNodeTreePath *, path, &snode.treepath) {
|
||||
const bNodeTree *ntree = path->nodetree;
|
||||
if (group_node_name) {
|
||||
node = group_node_by_name(*ntree, group_node_name);
|
||||
}
|
||||
bool found = false;
|
||||
for (const bNestedNodeRef &ref : ntree->nested_node_refs_span()) {
|
||||
if (node->is_group()) {
|
||||
if (ref.path.node_id == node->identifier && ref.path.id_in_node == id_in_node) {
|
||||
group_node_name = path->node_name;
|
||||
id_in_node = ref.id;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (ref.path.node_id == node->identifier) {
|
||||
group_node_name = path->node_name;
|
||||
id_in_node = ref.id;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
return id_in_node;
|
||||
}
|
||||
|
||||
/* ******************** default callbacks for node space ***************** */
|
||||
|
||||
static SpaceLink *node_create(const ScrArea * /*area*/, const Scene * /*scene*/)
|
||||
|
@ -2332,6 +2332,20 @@ typedef struct NodesModifierSettings {
|
||||
struct IDProperty *properties;
|
||||
} NodesModifierSettings;
|
||||
|
||||
typedef struct NodesModifierBake {
|
||||
int id;
|
||||
/** #NodesModifierBakeType. */
|
||||
uint32_t bake_type;
|
||||
int frame_start;
|
||||
int frame_end;
|
||||
char *directory;
|
||||
} NodesModifierBake;
|
||||
|
||||
typedef enum NodesModifierBakeType {
|
||||
NODES_MODIFIER_BAKE_TYPE_STILL = 0,
|
||||
NODES_MODIFIER_BAKE_TYPE_ANIMATED = 1,
|
||||
} NodesModifierBakeFlag;
|
||||
|
||||
typedef struct NodesModifierData {
|
||||
ModifierData modifier;
|
||||
struct bNodeTree *node_group;
|
||||
@ -2340,7 +2354,13 @@ typedef struct NodesModifierData {
|
||||
* Directory where baked simulation states are stored. This may be relative to the .blend file.
|
||||
*/
|
||||
char *simulation_bake_directory;
|
||||
|
||||
int active_bake;
|
||||
int bakes_num;
|
||||
NodesModifierBake *bakes;
|
||||
|
||||
NodesModifierRuntimeHandle *runtime;
|
||||
void *_pad2;
|
||||
} NodesModifierData;
|
||||
|
||||
typedef struct MeshToVolumeModifierData {
|
||||
|
@ -709,8 +709,9 @@ typedef struct bNodeTree {
|
||||
const bNestedNodeRef *find_nested_node_ref(int32_t nested_node_id) const;
|
||||
/** Conversions between node id paths and their corresponding nested node ref. */
|
||||
const bNestedNodeRef *nested_node_ref_from_node_id_path(blender::Span<int> node_ids) const;
|
||||
[[nodiscard]] bool node_id_path_from_nested_node_ref(const int32_t nested_node_id,
|
||||
[[nodiscard]] bool node_id_path_from_nested_node_ref(int32_t nested_node_id,
|
||||
blender::Vector<int32_t> &r_node_ids) const;
|
||||
const bNode *find_nested_node(int32_t nested_node_id) const;
|
||||
|
||||
/**
|
||||
* Update a run-time cache for the node tree based on it's current state. This makes many methods
|
||||
@ -1827,6 +1828,39 @@ typedef struct NodeGeometryRepeatOutput {
|
||||
#endif
|
||||
} NodeGeometryRepeatOutput;
|
||||
|
||||
typedef struct NodeGeometryBakeItem {
|
||||
char *name;
|
||||
/** #eNodeSocketDatatype. */
|
||||
short socket_type;
|
||||
/** #eAttrDomain. */
|
||||
short attribute_domain;
|
||||
/**
|
||||
* Generated unique identifier for sockets which stays the same even when the item order or
|
||||
* names change.
|
||||
*/
|
||||
int identifier;
|
||||
|
||||
#ifdef __cplusplus
|
||||
static bool supports_type(eNodeSocketDatatype type);
|
||||
std::string identifier_str() const;
|
||||
#endif
|
||||
} NodeGeometryBakeItem;
|
||||
|
||||
typedef struct NodeGeometryBake {
|
||||
NodeGeometryBakeItem *items;
|
||||
int items_num;
|
||||
int active_index;
|
||||
int next_identifier;
|
||||
char _pad[4];
|
||||
|
||||
#ifdef __cplusplus
|
||||
blender::Span<NodeGeometryBakeItem> items_span() const;
|
||||
blender::MutableSpan<NodeGeometryBakeItem> items_span();
|
||||
NodeGeometryBakeItem *add_item(const char *name, eNodeSocketDatatype type);
|
||||
void set_item_name(NodeGeometryBakeItem &item, const char *name);
|
||||
#endif
|
||||
} NodeGeometryBake;
|
||||
|
||||
typedef struct NodeGeometryDistributePointsInVolume {
|
||||
/** #GeometryNodePointDistributeVolumeMode. */
|
||||
uint8_t mode;
|
||||
|
@ -7050,11 +7050,72 @@ static void rna_def_modifier_weightednormal(BlenderRNA *brna)
|
||||
RNA_define_lib_overridable(false);
|
||||
}
|
||||
|
||||
static void rna_def_modifier_nodes_bake(BlenderRNA *brna)
|
||||
{
|
||||
static EnumPropertyItem bake_type_items[] = {
|
||||
{NODES_MODIFIER_BAKE_TYPE_STILL,
|
||||
"STILL",
|
||||
0,
|
||||
"Still",
|
||||
"Bake the geometry at one frame and use it for all frames"},
|
||||
{NODES_MODIFIER_BAKE_TYPE_ANIMATED,
|
||||
"ANIMATED",
|
||||
0,
|
||||
"Animated",
|
||||
"Bake the geometry at multiple frames"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "NodesModifierBake", nullptr);
|
||||
RNA_def_struct_ui_text(srna, "Nodes Modifier Bake", "");
|
||||
|
||||
prop = RNA_def_property(srna, "directory", PROP_STRING, PROP_DIRPATH);
|
||||
RNA_def_property_ui_text(prop, "Directory", "Location on disk where the bake data is stored");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "bake_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Bake Type", "");
|
||||
RNA_def_property_enum_items(prop, bake_type_items);
|
||||
RNA_def_property_update(prop, 0, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Frame Start", "Frame to start baking at");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, 0, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "frame_end", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Frame End", "Frame to end baking at");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, 0, nullptr);
|
||||
}
|
||||
|
||||
static void rna_def_modifier_nodes_bakes(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "NodesModifierBakes", nullptr);
|
||||
RNA_def_struct_sdna(srna, "NodesModifierData");
|
||||
RNA_def_struct_ui_text(srna, "Bakes", "Bake data for every bake node");
|
||||
|
||||
prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, nullptr, "active_bake");
|
||||
RNA_def_property_ui_text(prop, "Active Bake Index", "");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, 0, nullptr);
|
||||
}
|
||||
|
||||
static void rna_def_modifier_nodes(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
rna_def_modifier_nodes_bake(brna);
|
||||
rna_def_modifier_nodes_bakes(brna);
|
||||
|
||||
srna = RNA_def_struct(brna, "NodesModifier", "Modifier");
|
||||
RNA_def_struct_ui_text(srna, "Nodes Modifier", "");
|
||||
RNA_def_struct_sdna(srna, "NodesModifierData");
|
||||
@ -7075,6 +7136,11 @@ static void rna_def_modifier_nodes(BlenderRNA *brna)
|
||||
prop, "Simulation Bake Directory", "Location on disk where the bake data is stored");
|
||||
RNA_def_property_update(prop, 0, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "bakes", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "NodesModifierBake");
|
||||
RNA_def_property_collection_sdna(prop, nullptr, "bakes", "bakes_num");
|
||||
RNA_def_property_srna(prop, "NodesModifierBakes");
|
||||
|
||||
RNA_define_lib_overridable(false);
|
||||
}
|
||||
|
||||
|
@ -3151,6 +3151,20 @@ static bNode *find_node_by_repeat_item(PointerRNA *ptr)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bNode *find_node_by_bake_item(PointerRNA *ptr)
|
||||
{
|
||||
const NodeGeometryBakeItem *item = static_cast<const NodeGeometryBakeItem *>(ptr->data);
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(ptr->owner_id);
|
||||
ntree->ensure_topology_cache();
|
||||
for (bNode *node : ntree->nodes_by_type("GeometryNodeBake")) {
|
||||
auto *storage = static_cast<NodeGeometryBake *>(node->storage);
|
||||
if (storage->items_span().contains_ptr(item)) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void rna_RepeatItem_update(Main *bmain, Scene * /*scene*/, PointerRNA *ptr)
|
||||
{
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(ptr->owner_id);
|
||||
@ -3160,6 +3174,15 @@ static void rna_RepeatItem_update(Main *bmain, Scene * /*scene*/, PointerRNA *pt
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
}
|
||||
|
||||
static void rna_NodeGeometryBakeItem_update(Main *bmain, Scene * /*scene*/, PointerRNA *ptr)
|
||||
{
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(ptr->owner_id);
|
||||
bNode *node = find_node_by_bake_item(ptr);
|
||||
|
||||
BKE_ntree_update_tag_node_property(ntree, node);
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
}
|
||||
|
||||
static bool rna_SimulationStateItem_socket_type_supported(const EnumPropertyItem *item)
|
||||
{
|
||||
return NOD_geometry_simulation_output_item_socket_type_supported(
|
||||
@ -3191,6 +3214,21 @@ static const EnumPropertyItem *rna_RepeatItem_socket_type_itemf(bContext * /*C*/
|
||||
rna_RepeatItem_socket_type_supported);
|
||||
}
|
||||
|
||||
static bool rna_NodeGeometryBakeItem_socket_type_supported(const EnumPropertyItem *item)
|
||||
{
|
||||
return NodeGeometryBakeItem::supports_type(eNodeSocketDatatype(item->value));
|
||||
}
|
||||
|
||||
static const EnumPropertyItem *rna_NodeGeometryBakeItem_socket_type_itemf(bContext * /*C*/,
|
||||
PointerRNA * /*ptr*/,
|
||||
PropertyRNA * /*prop*/,
|
||||
bool *r_free)
|
||||
{
|
||||
*r_free = true;
|
||||
return itemf_function_check(rna_enum_node_socket_data_type_items,
|
||||
rna_NodeGeometryBakeItem_socket_type_supported);
|
||||
}
|
||||
|
||||
static void rna_SimulationStateItem_name_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(ptr->owner_id);
|
||||
@ -3210,6 +3248,14 @@ static void rna_RepeatItem_name_set(PointerRNA *ptr, const char *value)
|
||||
storage->set_item_name(*item, value);
|
||||
}
|
||||
|
||||
static void rna_NodeGeometryBakeItem_name_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
bNode *node = find_node_by_bake_item(ptr);
|
||||
NodeGeometryBakeItem *item = static_cast<NodeGeometryBakeItem *>(ptr->data);
|
||||
auto *storage = static_cast<NodeGeometryBake *>(node->storage);
|
||||
storage->set_item_name(*item, value);
|
||||
}
|
||||
|
||||
static void rna_SimulationStateItem_color_get(PointerRNA *ptr, float *values)
|
||||
{
|
||||
NodeSimulationItem *item = static_cast<NodeSimulationItem *>(ptr->data);
|
||||
@ -3226,6 +3272,14 @@ static void rna_RepeatItem_color_get(PointerRNA *ptr, float *values)
|
||||
ED_node_type_draw_color(socket_type_idname, values);
|
||||
}
|
||||
|
||||
static void rna_NodeGeometryBakeItem_color_get(PointerRNA *ptr, float *values)
|
||||
{
|
||||
NodeGeometryBakeItem *item = static_cast<NodeGeometryBakeItem *>(ptr->data);
|
||||
|
||||
const char *socket_type_idname = nodeStaticSocketType(item->socket_type, 0);
|
||||
ED_node_type_draw_color(socket_type_idname, values);
|
||||
}
|
||||
|
||||
static PointerRNA rna_NodeGeometrySimulationInput_paired_output_get(PointerRNA *ptr)
|
||||
{
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(ptr->owner_id);
|
||||
@ -3327,6 +3381,24 @@ static NodeRepeatItem *rna_NodeGeometryRepeatOutput_items_new(
|
||||
return item;
|
||||
}
|
||||
|
||||
static NodeGeometryBakeItem *rna_NodeGeometryBake_items_new(
|
||||
ID *id, bNode *node, Main *bmain, ReportList *reports, int socket_type, const char *name)
|
||||
{
|
||||
NodeGeometryBake *storage = static_cast<NodeGeometryBake *>(node->storage);
|
||||
NodeGeometryBakeItem *item = storage->add_item(name, eNodeSocketDatatype(socket_type));
|
||||
if (item == nullptr) {
|
||||
BKE_report(reports, RPT_ERROR, "Unable to create socket");
|
||||
}
|
||||
else {
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
|
||||
BKE_ntree_update_tag_node_property(ntree, node);
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
static void rna_NodeGeometrySimulationOutput_items_remove(
|
||||
ID *id, bNode *node, Main *bmain, ReportList *reports, NodeSimulationItem *item)
|
||||
{
|
||||
@ -3371,6 +3443,33 @@ static void rna_NodeGeometryRepeatOutput_items_remove(
|
||||
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
|
||||
}
|
||||
|
||||
static void rna_NodeGeometryBake_items_remove(
|
||||
ID *id, bNode *node, Main *bmain, ReportList *reports, NodeGeometryBakeItem *item)
|
||||
{
|
||||
NodeGeometryBake *storage = static_cast<NodeGeometryBake *>(node->storage);
|
||||
if (!storage->items_span().contains_ptr(item)) {
|
||||
BKE_reportf(reports, RPT_ERROR, "Unable to locate item '%s' in node", item->name);
|
||||
return;
|
||||
}
|
||||
|
||||
const int remove_index = item - storage->items;
|
||||
NodeGeometryBakeItem *old_items = storage->items;
|
||||
storage->items = MEM_cnew_array<NodeGeometryBakeItem>(storage->items_num - 1, __func__);
|
||||
std::copy_n(old_items, remove_index, storage->items);
|
||||
std::copy_n(old_items + remove_index + 1,
|
||||
storage->items_num - remove_index - 1,
|
||||
storage->items + remove_index);
|
||||
|
||||
MEM_SAFE_FREE(old_items[remove_index].name);
|
||||
storage->items_num--;
|
||||
MEM_SAFE_FREE(old_items);
|
||||
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
|
||||
BKE_ntree_update_tag_node_property(ntree, node);
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
|
||||
}
|
||||
|
||||
static void rna_NodeGeometrySimulationOutput_items_clear(ID *id, bNode *node, Main *bmain)
|
||||
{
|
||||
NodeGeometrySimulationOutput *sim = static_cast<NodeGeometrySimulationOutput *>(node->storage);
|
||||
@ -3393,6 +3492,17 @@ static void rna_NodeGeometryRepeatOutput_items_clear(ID * /*id*/, bNode *node, M
|
||||
storage->active_index = 0;
|
||||
}
|
||||
|
||||
static void rna_NodeGeometryBake_items_clear(ID * /*id*/, bNode *node, Main * /*bmain*/)
|
||||
{
|
||||
NodeGeometryBake *storage = static_cast<NodeGeometryBake *>(node->storage);
|
||||
for (NodeGeometryBakeItem &item : storage->items_span()) {
|
||||
MEM_SAFE_FREE(item.name);
|
||||
}
|
||||
MEM_SAFE_FREE(storage->items);
|
||||
storage->items_num = 0;
|
||||
storage->active_index = 0;
|
||||
}
|
||||
|
||||
static void rna_NodeGeometrySimulationOutput_items_move(
|
||||
ID *id, bNode *node, Main *bmain, int from_index, int to_index)
|
||||
{
|
||||
@ -3442,6 +3552,37 @@ static void rna_NodeGeometryRepeatOutput_items_move(
|
||||
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
|
||||
}
|
||||
|
||||
static void rna_NodeGeometryBake_items_move(
|
||||
ID *id, bNode *node, Main *bmain, int from_index, int to_index)
|
||||
{
|
||||
NodeGeometryBake *storage = static_cast<NodeGeometryBake *>(node->storage);
|
||||
if (from_index < 0 || from_index >= storage->items_num || to_index < 0 ||
|
||||
to_index >= storage->items_num)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (from_index < to_index) {
|
||||
const NodeGeometryBakeItem tmp = storage->items[from_index];
|
||||
for (int i = from_index; i < to_index; i++) {
|
||||
storage->items[i] = storage->items[i + 1];
|
||||
}
|
||||
storage->items[to_index] = tmp;
|
||||
}
|
||||
else if (from_index > to_index) {
|
||||
const NodeGeometryBakeItem tmp = storage->items[from_index];
|
||||
for (int i = from_index; i > to_index; i--) {
|
||||
storage->items[i] = storage->items[i - 1];
|
||||
}
|
||||
storage->items[to_index] = tmp;
|
||||
}
|
||||
|
||||
bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
|
||||
BKE_ntree_update_tag_node_property(ntree, node);
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
|
||||
}
|
||||
|
||||
static PointerRNA rna_NodeGeometrySimulationOutput_active_item_get(PointerRNA *ptr)
|
||||
{
|
||||
bNode *node = static_cast<bNode *>(ptr->data);
|
||||
@ -3464,6 +3605,19 @@ static PointerRNA rna_NodeGeometryRepeatOutput_active_item_get(PointerRNA *ptr)
|
||||
return r_ptr;
|
||||
}
|
||||
|
||||
static PointerRNA rna_NodeGeometryBake_active_item_get(PointerRNA *ptr)
|
||||
{
|
||||
bNode *node = static_cast<bNode *>(ptr->data);
|
||||
NodeGeometryBake *storage = static_cast<NodeGeometryBake *>(node->storage);
|
||||
blender::MutableSpan<NodeGeometryBakeItem> items = storage->items_span();
|
||||
PointerRNA r_ptr{};
|
||||
if (items.index_range().contains(storage->active_index)) {
|
||||
RNA_pointer_create(
|
||||
ptr->owner_id, &RNA_NodeGeometryBakeItem, &items[storage->active_index], &r_ptr);
|
||||
}
|
||||
return r_ptr;
|
||||
}
|
||||
|
||||
static void rna_NodeGeometrySimulationOutput_active_item_set(PointerRNA *ptr,
|
||||
PointerRNA value,
|
||||
ReportList * /*reports*/)
|
||||
@ -3486,6 +3640,18 @@ static void rna_NodeGeometryRepeatOutput_active_item_set(PointerRNA *ptr,
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_NodeGeometryBake_active_item_set(PointerRNA *ptr,
|
||||
PointerRNA value,
|
||||
ReportList * /*reports*/)
|
||||
{
|
||||
bNode *node = static_cast<bNode *>(ptr->data);
|
||||
NodeGeometryBake *storage = static_cast<NodeGeometryBake *>(node->storage);
|
||||
NodeGeometryBakeItem *item = static_cast<NodeGeometryBakeItem *>(value.data);
|
||||
if (storage->items_span().contains_ptr(item)) {
|
||||
storage->active_index = item - storage->items;
|
||||
}
|
||||
}
|
||||
|
||||
/* ******** Node Socket Types ******** */
|
||||
|
||||
static PointerRNA rna_NodeOutputFile_slot_layer_get(CollectionPropertyIterator *iter)
|
||||
@ -9126,6 +9292,120 @@ static void def_geo_repeat_output(StructRNA *srna)
|
||||
RNA_def_property_update(prop, NC_NODE, nullptr);
|
||||
}
|
||||
|
||||
static void rna_def_bake_item(BlenderRNA *brna)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
StructRNA *srna = RNA_def_struct(brna, "NodeGeometryBakeItem", nullptr);
|
||||
RNA_def_struct_ui_text(srna, "Bake Item", "");
|
||||
RNA_def_struct_sdna(srna, "NodeGeometryBakeItem");
|
||||
|
||||
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_funcs(prop, nullptr, nullptr, "rna_NodeGeometryBakeItem_name_set");
|
||||
RNA_def_property_ui_text(prop, "Name", "");
|
||||
RNA_def_struct_name_property(srna, prop);
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeGeometryBakeItem_update");
|
||||
|
||||
prop = RNA_def_property(srna, "socket_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, rna_enum_node_socket_data_type_items);
|
||||
RNA_def_property_enum_funcs(
|
||||
prop, nullptr, nullptr, "rna_NodeGeometryBakeItem_socket_type_itemf");
|
||||
RNA_def_property_ui_text(prop, "Socket Type", "");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeGeometryBakeItem_update");
|
||||
|
||||
prop = RNA_def_property(srna, "attribute_domain", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Attribute Domain", "Attribute domain where the attribute is stored");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeGeometryBakeItem_update");
|
||||
|
||||
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
|
||||
RNA_def_property_array(prop, 4);
|
||||
RNA_def_property_float_funcs(prop, "rna_NodeGeometryBakeItem_color_get", nullptr, nullptr);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Color", "Color of the corresponding socket type in the node editor");
|
||||
}
|
||||
|
||||
static void rna_def_geo_bake_items(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *parm;
|
||||
FunctionRNA *func;
|
||||
|
||||
srna = RNA_def_struct(brna, "NodeGeometryBakeItems", nullptr);
|
||||
RNA_def_struct_sdna(srna, "bNode");
|
||||
RNA_def_struct_ui_text(srna, "Items", "Collection of bake items");
|
||||
|
||||
func = RNA_def_function(srna, "new", "rna_NodeGeometryBake_items_new");
|
||||
RNA_def_function_ui_description(func, "Add a item to this bake node");
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
|
||||
parm = RNA_def_enum(func,
|
||||
"socket_type",
|
||||
rna_enum_node_socket_data_type_items,
|
||||
SOCK_GEOMETRY,
|
||||
"Socket Type",
|
||||
"Socket type of the item");
|
||||
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
|
||||
parm = RNA_def_string(func, "name", nullptr, MAX_NAME, "Name", "");
|
||||
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
|
||||
/* return value */
|
||||
parm = RNA_def_pointer(func, "item", "NodeGeometryBakeItem", "Item", "New item");
|
||||
RNA_def_function_return(func, parm);
|
||||
|
||||
func = RNA_def_function(srna, "remove", "rna_NodeGeometryBake_items_remove");
|
||||
RNA_def_function_ui_description(func, "Remove an item from this bake node");
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
|
||||
parm = RNA_def_pointer(func, "item", "NodeGeometryBakeItem", "Item", "The item to remove");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
|
||||
|
||||
func = RNA_def_function(srna, "clear", "rna_NodeGeometryBake_items_clear");
|
||||
RNA_def_function_ui_description(func, "Remove all items from this bake node");
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
|
||||
|
||||
func = RNA_def_function(srna, "move", "rna_NodeGeometryBake_items_move");
|
||||
RNA_def_function_ui_description(func, "Move an item to another position");
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
|
||||
parm = RNA_def_int(
|
||||
func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the item to move", 0, 10000);
|
||||
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
|
||||
parm = RNA_def_int(
|
||||
func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the item", 0, 10000);
|
||||
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
|
||||
}
|
||||
|
||||
static void def_geo_bake(StructRNA *srna)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
RNA_def_struct_sdna_from(srna, "NodeGeometryBake", "storage");
|
||||
|
||||
prop = RNA_def_property(srna, "bake_items", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_collection_sdna(prop, nullptr, "items", "items_num");
|
||||
RNA_def_property_struct_type(prop, "NodeGeometryBakeItem");
|
||||
RNA_def_property_ui_text(prop, "Items", "");
|
||||
RNA_def_property_srna(prop, "NodeGeometryBakeItems");
|
||||
|
||||
prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_int_sdna(prop, nullptr, "active_index");
|
||||
RNA_def_property_ui_text(prop, "Active Item Index", "");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_NODE, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "active_item", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "NodeGeometryBakeItem");
|
||||
RNA_def_property_pointer_funcs(prop,
|
||||
"rna_NodeGeometryBake_active_item_get",
|
||||
"rna_NodeGeometryBake_active_item_set",
|
||||
nullptr,
|
||||
nullptr);
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(prop, "Active Item", "");
|
||||
RNA_def_property_update(prop, NC_NODE, nullptr);
|
||||
}
|
||||
|
||||
static void def_geo_curve_handle_type_selection(StructRNA *srna)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
@ -10440,6 +10720,7 @@ void RNA_def_nodetree(BlenderRNA *brna)
|
||||
|
||||
rna_def_simulation_state_item(brna);
|
||||
rna_def_repeat_item(brna);
|
||||
rna_def_bake_item(brna);
|
||||
|
||||
# define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \
|
||||
{ \
|
||||
@ -10492,6 +10773,7 @@ void RNA_def_nodetree(BlenderRNA *brna)
|
||||
rna_def_cmp_output_file_slot_layer(brna);
|
||||
rna_def_geo_simulation_output_items(brna);
|
||||
rna_def_geo_repeat_output_items(brna);
|
||||
rna_def_geo_bake_items(brna);
|
||||
|
||||
rna_def_node_instance_hash(brna);
|
||||
}
|
||||
|
@ -66,6 +66,7 @@
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
@ -383,11 +384,8 @@ static bool logging_enabled(const ModifierEvalContext *ctx)
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
|
||||
void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
|
||||
static void update_id_properties_from_node_group(NodesModifierData *nmd)
|
||||
{
|
||||
using namespace blender;
|
||||
if (nmd->node_group == nullptr) {
|
||||
if (nmd->settings.properties) {
|
||||
IDP_FreeProperty(nmd->settings.properties);
|
||||
@ -411,6 +409,66 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
|
||||
if (old_properties != nullptr) {
|
||||
IDP_FreeProperty(old_properties);
|
||||
}
|
||||
}
|
||||
|
||||
static void update_bakes_from_node_group(NodesModifierData &nmd)
|
||||
{
|
||||
Map<int, const NodesModifierBake *> old_bake_by_id;
|
||||
for (const NodesModifierBake &bake : Span(nmd.bakes, nmd.bakes_num)) {
|
||||
old_bake_by_id.add(bake.id, &bake);
|
||||
}
|
||||
|
||||
Vector<int> new_bake_ids;
|
||||
for (const bNestedNodeRef &ref : nmd.node_group->nested_node_refs_span()) {
|
||||
const bNode *node = nmd.node_group->find_nested_node(ref.id);
|
||||
if (node) {
|
||||
if (node->type == GEO_NODE_BAKE) {
|
||||
new_bake_ids.append(ref.id);
|
||||
}
|
||||
}
|
||||
else if (old_bake_by_id.contains(ref.id)) {
|
||||
/* Keep baked data in case linked data is missing so that it still exists when the linked
|
||||
* data has been found. */
|
||||
new_bake_ids.append(ref.id);
|
||||
}
|
||||
}
|
||||
|
||||
NodesModifierBake *new_bake_data = static_cast<NodesModifierBake *>(
|
||||
MEM_callocN(sizeof(NodesModifierBake) * new_bake_ids.size(), __func__));
|
||||
for (const int i : new_bake_ids.index_range()) {
|
||||
const int id = new_bake_ids[i];
|
||||
const NodesModifierBake *old_bake = old_bake_by_id.lookup_default(id, nullptr);
|
||||
NodesModifierBake &new_bake = new_bake_data[i];
|
||||
if (old_bake) {
|
||||
new_bake = *old_bake;
|
||||
if (new_bake.directory) {
|
||||
new_bake.directory = BLI_strdup(new_bake.directory);
|
||||
}
|
||||
}
|
||||
else {
|
||||
new_bake.id = id;
|
||||
new_bake.frame_start = 1;
|
||||
new_bake.frame_end = 100;
|
||||
}
|
||||
}
|
||||
|
||||
for (NodesModifierBake &old_bake : MutableSpan(nmd.bakes, nmd.bakes_num)) {
|
||||
MEM_SAFE_FREE(old_bake.directory);
|
||||
}
|
||||
MEM_SAFE_FREE(nmd.bakes);
|
||||
|
||||
nmd.bakes = new_bake_data;
|
||||
nmd.bakes_num = new_bake_ids.size();
|
||||
nmd.active_bake = std::max(0, std::min(nmd.bakes_num - 1, nmd.active_bake));
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
|
||||
void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
|
||||
{
|
||||
using namespace blender;
|
||||
update_id_properties_from_node_group(nmd);
|
||||
update_bakes_from_node_group(*nmd);
|
||||
|
||||
DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
|
||||
}
|
||||
@ -557,11 +615,90 @@ static void find_side_effect_nodes_for_viewer_path(
|
||||
}
|
||||
}
|
||||
|
||||
static void find_side_effect_nodes_for_nested_node_ref(
|
||||
const bNestedNodeRef &node_ref,
|
||||
const NodesModifierData &nmd,
|
||||
MultiValueMap<ComputeContextHash, const lf::FunctionNode *> &r_side_effect_nodes)
|
||||
{
|
||||
ComputeContextBuilder compute_context_builder;
|
||||
compute_context_builder.push<bke::ModifierComputeContext>(nmd.modifier.name);
|
||||
|
||||
/* Write side effect nodes to a new map and only add them to r_side_effect_nodes if this function
|
||||
* does not return early. */
|
||||
MultiValueMap<ComputeContextHash, const lf::FunctionNode *> local_side_effect_nodes;
|
||||
|
||||
const bNodeTree *group = nmd.node_group;
|
||||
Vector<int32_t> node_id_path;
|
||||
if (!group->node_id_path_from_nested_node_ref(node_ref.id, node_id_path)) {
|
||||
return;
|
||||
}
|
||||
for (const int32_t node_id : node_id_path) {
|
||||
const bNode *node = group->node_by_id(node_id);
|
||||
if (node == nullptr) {
|
||||
return;
|
||||
}
|
||||
const bke::bNodeTreeZones *tree_zones = group->zones();
|
||||
if (tree_zones == nullptr) {
|
||||
return;
|
||||
}
|
||||
const auto lf_graph_info = nodes::ensure_geometry_nodes_lazy_function_graph(*group);
|
||||
if (lf_graph_info == nullptr) {
|
||||
return;
|
||||
}
|
||||
const bke::bNodeTreeZone *zone = tree_zones->get_zone_by_node(node_id);
|
||||
if (zone != nullptr) {
|
||||
/* Referenced node must be outside of any zone to be able to make it a side effect node. */
|
||||
return;
|
||||
}
|
||||
if (node->is_group()) {
|
||||
if (node->id == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (node->is_muted()) {
|
||||
return;
|
||||
}
|
||||
const lf::FunctionNode *lf_group_node = lf_graph_info->mapping.group_node_map.lookup_default(
|
||||
node, nullptr);
|
||||
if (lf_group_node == nullptr) {
|
||||
return;
|
||||
}
|
||||
local_side_effect_nodes.add(compute_context_builder.hash(), lf_group_node);
|
||||
compute_context_builder.push<bke::NodeGroupComputeContext>(*node);
|
||||
group = reinterpret_cast<const bNodeTree *>(node->id);
|
||||
}
|
||||
else {
|
||||
const lf::FunctionNode *lf_bake_node = lf_graph_info->mapping.bake_node_map.lookup_default(
|
||||
node, nullptr);
|
||||
if (lf_bake_node == nullptr) {
|
||||
return;
|
||||
}
|
||||
local_side_effect_nodes.add(compute_context_builder.hash(), lf_bake_node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Successfully found all compute contexts for the nested node. */
|
||||
for (const auto item : local_side_effect_nodes.items()) {
|
||||
r_side_effect_nodes.add_multiple(item.key, item.value);
|
||||
}
|
||||
}
|
||||
|
||||
static void find_side_effect_nodes(
|
||||
const NodesModifierData &nmd,
|
||||
const ModifierEvalContext &ctx,
|
||||
MultiValueMap<ComputeContextHash, const lf::FunctionNode *> &r_side_effect_nodes)
|
||||
{
|
||||
// if (nmd.runtime->bakes) {
|
||||
// std::lock_guard lock{nmd.runtime->bakes->mutex};
|
||||
// for (const auto item : nmd.runtime->bakes->storage_by_id.items()) {
|
||||
// if (item.value->current_bake_state) {
|
||||
// const bNestedNodeRef *node_ref = nmd.node_group->find_nested_node_ref(item.key);
|
||||
// BLI_assert(node_ref != nullptr);
|
||||
// find_side_effect_nodes_for_nested_node_ref(*node_ref, nmd, r_side_effect_nodes);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
Main *bmain = DEG_get_bmain(ctx.depsgraph);
|
||||
wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
|
||||
if (wm == nullptr) {
|
||||
@ -1068,6 +1205,7 @@ static void modifyGeometry(ModifierData *md,
|
||||
}
|
||||
|
||||
nodes::GeoNodesModifierData modifier_eval_data{};
|
||||
modifier_eval_data.nmd = nmd;
|
||||
modifier_eval_data.depsgraph = ctx->depsgraph;
|
||||
modifier_eval_data.self_object = ctx->object;
|
||||
auto eval_log = std::make_unique<geo_log::GeoModifierLog>();
|
||||
@ -1086,8 +1224,24 @@ static void modifyGeometry(ModifierData *md,
|
||||
find_side_effect_nodes(*nmd, *ctx, side_effect_nodes);
|
||||
modifier_eval_data.side_effect_nodes = &side_effect_nodes;
|
||||
|
||||
bke::ModifierComputeContext modifier_compute_context{nullptr, nmd->modifier.name};
|
||||
{
|
||||
for (const bNestedNodeRef &node_ref : nmd->node_group->nested_node_refs_span()) {
|
||||
Vector<int32_t> node_ids;
|
||||
if (!nmd->node_group->node_id_path_from_nested_node_ref(node_ref.id, node_ids)) {
|
||||
continue;
|
||||
}
|
||||
ComputeContextBuilder compute_context_builder;
|
||||
compute_context_builder.push<bke::ModifierComputeContext>(nmd->modifier.name);
|
||||
const int32_t leaf_node_id = node_ids.pop_last();
|
||||
for (const int32_t node_id : node_ids.as_span()) {
|
||||
compute_context_builder.push<bke::NodeGroupComputeContext>(node_id);
|
||||
}
|
||||
modifier_eval_data.nested_node_id_by_compute_context.add(
|
||||
{compute_context_builder.hash(), leaf_node_id}, node_ref.id);
|
||||
}
|
||||
}
|
||||
|
||||
bke::ModifierComputeContext modifier_compute_context{nullptr, nmd->modifier.name};
|
||||
geometry_set = nodes::execute_geometry_nodes_on_geometry(
|
||||
tree,
|
||||
nmd->settings.properties,
|
||||
@ -1675,6 +1829,11 @@ static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const Modi
|
||||
* and don't necessarily need to be written, but we can't just free them. */
|
||||
IDP_BlendWrite(writer, nmd->settings.properties);
|
||||
|
||||
BLO_write_struct_array(writer, NodesModifierBake, nmd->bakes_num, nmd->bakes);
|
||||
for (const NodesModifierBake &bake : Span(nmd->bakes, nmd->bakes_num)) {
|
||||
BLO_write_string(writer, bake.directory);
|
||||
}
|
||||
|
||||
if (!BLO_write_is_undo(writer)) {
|
||||
LISTBASE_FOREACH (IDProperty *, prop, &nmd->settings.properties->data.group) {
|
||||
if (prop->type == IDP_INT) {
|
||||
@ -1701,6 +1860,12 @@ static void blend_read(BlendDataReader *reader, ModifierData *md)
|
||||
BLO_read_data_address(reader, &nmd->settings.properties);
|
||||
IDP_BlendDataRead(reader, &nmd->settings.properties);
|
||||
}
|
||||
|
||||
BLO_read_data_address(reader, &nmd->bakes);
|
||||
for (NodesModifierBake &bake : MutableSpan(nmd->bakes, nmd->bakes_num)) {
|
||||
BLO_read_data_address(reader, &bake.directory);
|
||||
}
|
||||
|
||||
nmd->runtime = MEM_new<NodesModifierRuntime>(__func__);
|
||||
nmd->runtime->cache = std::make_shared<bake::ModifierCache>();
|
||||
}
|
||||
@ -1712,6 +1877,16 @@ static void copy_data(const ModifierData *md, ModifierData *target, const int fl
|
||||
|
||||
BKE_modifier_copydata_generic(md, target, flag);
|
||||
|
||||
if (nmd->bakes) {
|
||||
tnmd->bakes = static_cast<NodesModifierBake *>(MEM_dupallocN(nmd->bakes));
|
||||
for (const int i : IndexRange(nmd->bakes_num)) {
|
||||
NodesModifierBake &bake = tnmd->bakes[i];
|
||||
if (bake.directory) {
|
||||
bake.directory = BLI_strdup(bake.directory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tnmd->runtime = MEM_new<NodesModifierRuntime>(__func__);
|
||||
|
||||
if (flag & LIB_ID_COPY_SET_COPIED_ON_WRITE) {
|
||||
@ -1741,6 +1916,11 @@ static void free_data(ModifierData *md)
|
||||
nmd->settings.properties = nullptr;
|
||||
}
|
||||
|
||||
for (NodesModifierBake &bake : MutableSpan(nmd->bakes, nmd->bakes_num)) {
|
||||
MEM_SAFE_FREE(bake.directory);
|
||||
}
|
||||
MEM_SAFE_FREE(nmd->bakes);
|
||||
|
||||
MEM_SAFE_FREE(nmd->simulation_bake_directory);
|
||||
MEM_delete(nmd->runtime);
|
||||
}
|
||||
|
@ -35,6 +35,7 @@
|
||||
|
||||
struct Object;
|
||||
struct Depsgraph;
|
||||
struct NodesModifierData;
|
||||
struct Scene;
|
||||
|
||||
namespace blender::nodes {
|
||||
@ -132,6 +133,7 @@ class GeoNodesSimulationParams {
|
||||
* Data that is passed into geometry nodes evaluation from the modifier.
|
||||
*/
|
||||
struct GeoNodesModifierData {
|
||||
const NodesModifierData *nmd = nullptr;
|
||||
/** Object that is currently evaluated. */
|
||||
const Object *self_object = nullptr;
|
||||
/** Depsgraph that is evaluating the modifier. */
|
||||
@ -154,6 +156,8 @@ struct GeoNodesModifierData {
|
||||
* If this is null, all socket values will be logged.
|
||||
*/
|
||||
const Set<ComputeContextHash> *socket_log_contexts = nullptr;
|
||||
|
||||
Map<std::pair<ComputeContextHash, int32_t>, int32_t> nested_node_id_by_compute_context;
|
||||
};
|
||||
|
||||
struct GeoNodesOperatorData {
|
||||
@ -275,6 +279,7 @@ struct GeometryNodeLazyFunctionGraphMapping {
|
||||
Map<const bNode *, const lf::FunctionNode *> group_node_map;
|
||||
Map<const bNode *, const lf::FunctionNode *> viewer_node_map;
|
||||
Map<const bke::bNodeTreeZone *, const lf::FunctionNode *> zone_node_map;
|
||||
Map<const bNode *, const lf::FunctionNode *> bake_node_map;
|
||||
|
||||
/* Indexed by #bNodeSocket::index_in_all_outputs. */
|
||||
Array<int> lf_input_index_for_output_bsocket_usage;
|
||||
@ -338,6 +343,9 @@ std::unique_ptr<LazyFunction> get_simulation_input_lazy_function(
|
||||
const bNode &node,
|
||||
GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info);
|
||||
std::unique_ptr<LazyFunction> get_switch_node_lazy_function(const bNode &node);
|
||||
std::unique_ptr<LazyFunction> get_bake_node_lazy_function(
|
||||
const bNode &node, GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info);
|
||||
std::unique_ptr<LazyFunction> get_bake_node_input_usage_lazy_function(const bNode &node);
|
||||
|
||||
struct FoundNestedNodeID {
|
||||
int id;
|
||||
|
@ -293,6 +293,7 @@ DefNode(FunctionNode, FN_NODE_VALUE_TO_STRING, 0, "VALUE_TO_STRING", ValueToStri
|
||||
DefNode(GeometryNode, GEO_NODE_ACCUMULATE_FIELD, 0, "ACCUMULATE_FIELD", AccumulateField, "Accumulate Field", "Add the values of an evaluated field together and output the running total for each element")
|
||||
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, 0, "ATTRIBUTE_DOMAIN_SIZE", AttributeDomainSize, "Domain Size", "Retrieve the number of elements in a geometry for each attribute domain")
|
||||
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_STATISTIC, 0, "ATTRIBUTE_STATISTIC",AttributeStatistic, "Attribute Statistic", "Calculate statistics about a data set from a field evaluated on a geometry")
|
||||
DefNode(GeometryNode, GEO_NODE_BAKE, def_geo_bake, "BAKE", Bake, "Bake", "Store the geometry to having to recompute it every time")
|
||||
DefNode(GeometryNode, GEO_NODE_BLUR_ATTRIBUTE, 0, "BLUR_ATTRIBUTE", BlurAttribute, "Blur Attribute", "Mix attribute values of neighboring elements")
|
||||
DefNode(GeometryNode, GEO_NODE_BOUNDING_BOX, 0, "BOUNDING_BOX", BoundBox, "Bounding Box", "Calculate the limits of a geometry's positions and generate a box mesh with those dimensions")
|
||||
DefNode(GeometryNode, GEO_NODE_CAPTURE_ATTRIBUTE, 0, "CAPTURE_ATTRIBUTE", CaptureAttribute, "Capture Attribute", "Store the result of a field on a geometry and output the data as a node socket. Allows remembering or interpolating data as the geometry changes, such as positions before deformation")
|
||||
|
@ -16,6 +16,7 @@ set(INC
|
||||
../../gpu
|
||||
../../imbuf
|
||||
../../makesrna
|
||||
../../modifiers
|
||||
../../render
|
||||
../../windowmanager
|
||||
../../../../extern/fmtlib/include
|
||||
@ -31,6 +32,7 @@ set(SRC
|
||||
nodes/node_geo_attribute_capture.cc
|
||||
nodes/node_geo_attribute_domain_size.cc
|
||||
nodes/node_geo_attribute_statistic.cc
|
||||
nodes/node_geo_bake.cc
|
||||
nodes/node_geo_blur_attribute.cc
|
||||
nodes/node_geo_boolean.cc
|
||||
nodes/node_geo_bounding_box.cc
|
||||
|
590
source/blender/nodes/geometry/nodes/node_geo_bake.cc
Normal file
590
source/blender/nodes/geometry/nodes/node_geo_bake.cc
Normal file
@ -0,0 +1,590 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
#include "BKE_bake_geometry_nodes_modifier.hh"
|
||||
#include "BKE_bake_items_socket.hh"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_scene.h"
|
||||
#include "BKE_screen.h"
|
||||
|
||||
#include "BLI_binary_search.hh"
|
||||
#include "BLI_path_util.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_string_utils.h"
|
||||
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "ED_node.hh"
|
||||
|
||||
#include "MOD_nodes.hh"
|
||||
|
||||
#include "NOD_socket.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_prototypes.h"
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
#include "WM_api.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_bake_cc {
|
||||
|
||||
NODE_STORAGE_FUNCS(NodeGeometryBake);
|
||||
|
||||
static std::unique_ptr<SocketDeclaration> socket_declaration_for_bake_item(
|
||||
const NodeGeometryBakeItem &item,
|
||||
const eNodeSocketInOut in_out,
|
||||
const int corresponding_input = -1)
|
||||
{
|
||||
const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
|
||||
|
||||
std::unique_ptr<SocketDeclaration> decl;
|
||||
|
||||
auto handle_field_decl = [&](SocketDeclaration &decl) {
|
||||
if (in_out == SOCK_IN) {
|
||||
decl.input_field_type = InputSocketFieldType::IsSupported;
|
||||
}
|
||||
else {
|
||||
decl.output_field_dependency = OutputFieldDependency::ForPartiallyDependentField(
|
||||
{corresponding_input});
|
||||
}
|
||||
};
|
||||
|
||||
switch (socket_type) {
|
||||
case SOCK_FLOAT:
|
||||
decl = std::make_unique<decl::Float>();
|
||||
handle_field_decl(*decl);
|
||||
break;
|
||||
case SOCK_VECTOR:
|
||||
decl = std::make_unique<decl::Vector>();
|
||||
handle_field_decl(*decl);
|
||||
break;
|
||||
case SOCK_RGBA:
|
||||
decl = std::make_unique<decl::Color>();
|
||||
handle_field_decl(*decl);
|
||||
break;
|
||||
case SOCK_BOOLEAN:
|
||||
decl = std::make_unique<decl::Bool>();
|
||||
handle_field_decl(*decl);
|
||||
break;
|
||||
case SOCK_ROTATION:
|
||||
decl = std::make_unique<decl::Rotation>();
|
||||
handle_field_decl(*decl);
|
||||
break;
|
||||
case SOCK_INT:
|
||||
decl = std::make_unique<decl::Int>();
|
||||
handle_field_decl(*decl);
|
||||
break;
|
||||
case SOCK_GEOMETRY:
|
||||
decl = std::make_unique<decl::Geometry>();
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
|
||||
decl->name = item.name ? item.name : "";
|
||||
decl->identifier = item.identifier_str();
|
||||
decl->in_out = in_out;
|
||||
return decl;
|
||||
}
|
||||
|
||||
static void node_declare_dynamic(const bNodeTree & /*node_tree*/,
|
||||
const bNode &node,
|
||||
NodeDeclaration &r_declaration)
|
||||
{
|
||||
const NodeGeometryBake &storage = node_storage(node);
|
||||
for (const int i : IndexRange(storage.items_num)) {
|
||||
const NodeGeometryBakeItem &item = storage.items[i];
|
||||
SocketDeclarationPtr input_decl = socket_declaration_for_bake_item(item, SOCK_IN);
|
||||
SocketDeclarationPtr output_decl = socket_declaration_for_bake_item(item, SOCK_OUT, i);
|
||||
r_declaration.inputs.append(input_decl.get());
|
||||
r_declaration.items.append(std::move(input_decl));
|
||||
r_declaration.outputs.append(output_decl.get());
|
||||
r_declaration.items.append(std::move(output_decl));
|
||||
}
|
||||
SocketDeclarationPtr input_extend_decl = decl::create_extend_declaration(SOCK_IN);
|
||||
SocketDeclarationPtr output_extend_decl = decl::create_extend_declaration(SOCK_OUT);
|
||||
r_declaration.inputs.append(input_extend_decl.get());
|
||||
r_declaration.items.append(std::move(input_extend_decl));
|
||||
r_declaration.outputs.append(output_extend_decl.get());
|
||||
r_declaration.items.append(std::move(output_extend_decl));
|
||||
|
||||
aal::RelationsInNode &relations =
|
||||
NodeDeclarationBuilder(r_declaration).get_anonymous_attribute_relations();
|
||||
int last_geometry_index = -1;
|
||||
for (const int i : IndexRange(storage.items_num)) {
|
||||
const NodeGeometryBakeItem &item = storage.items[i];
|
||||
if (item.socket_type == SOCK_GEOMETRY) {
|
||||
last_geometry_index = i;
|
||||
}
|
||||
else if (last_geometry_index != -1) {
|
||||
relations.eval_relations.append({i, last_geometry_index});
|
||||
relations.available_relations.append({i, last_geometry_index});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void node_init(bNodeTree * /*tree*/, bNode *node)
|
||||
{
|
||||
NodeGeometryBake *data = MEM_cnew<NodeGeometryBake>(__func__);
|
||||
data->next_identifier = 0;
|
||||
data->items = MEM_cnew_array<NodeGeometryBakeItem>(1, __func__);
|
||||
data->items[0].name = BLI_strdup(DATA_("Geometry"));
|
||||
data->items[0].socket_type = SOCK_GEOMETRY;
|
||||
data->items[0].identifier = data->next_identifier++;
|
||||
data->items_num = 1;
|
||||
|
||||
node->storage = data;
|
||||
}
|
||||
|
||||
static void node_free_storage(bNode *node)
|
||||
{
|
||||
NodeGeometryBake &storage = node_storage(*node);
|
||||
for (NodeGeometryBakeItem &item : storage.items_span()) {
|
||||
MEM_SAFE_FREE(item.name);
|
||||
}
|
||||
MEM_SAFE_FREE(storage.items);
|
||||
MEM_freeN(node->storage);
|
||||
}
|
||||
|
||||
static void node_copy_storage(bNodeTree * /*dst_tree*/, bNode *dst_node, const bNode *src_node)
|
||||
{
|
||||
const NodeGeometryBake &src_storage = node_storage(*src_node);
|
||||
NodeGeometryBake *dst_storage = MEM_new<NodeGeometryBake>(__func__, src_storage);
|
||||
|
||||
dst_storage->items = MEM_cnew_array<NodeGeometryBakeItem>(src_storage.items_num, __func__);
|
||||
for (const int i : IndexRange(src_storage.items_num)) {
|
||||
dst_storage->items[i] = src_storage.items[i];
|
||||
if (dst_storage->items[i].name) {
|
||||
dst_storage->items[i].name = BLI_strdup(dst_storage->items[i].name);
|
||||
}
|
||||
}
|
||||
dst_node->storage = dst_storage;
|
||||
}
|
||||
|
||||
static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
|
||||
{
|
||||
NodeGeometryBake &storage = node_storage(*node);
|
||||
if (link->tonode == node) {
|
||||
if (link->tosock->identifier == StringRef("__extend__")) {
|
||||
if (const NodeGeometryBakeItem *item = storage.add_item(
|
||||
link->fromsock->name, eNodeSocketDatatype(link->fromsock->type)))
|
||||
{
|
||||
update_node_declaration_and_sockets(*ntree, *node);
|
||||
link->tosock = nodeFindSocket(node, SOCK_IN, item->identifier_str().c_str());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (link->fromnode == node) {
|
||||
if (link->fromsock->identifier == StringRef("__extend__")) {
|
||||
if (const NodeGeometryBakeItem *item = storage.add_item(
|
||||
link->tosock->name, eNodeSocketDatatype(link->tosock->type)))
|
||||
{
|
||||
update_node_declaration_and_sockets(*ntree, *node);
|
||||
link->fromsock = nodeFindSocket(node, SOCK_OUT, item->identifier_str().c_str());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static NodesModifierBake *get_bake(NodesModifierData &nmd, const int32_t bake_id)
|
||||
{
|
||||
for (NodesModifierBake &bake : MutableSpan(nmd.bakes, nmd.bakes_num)) {
|
||||
if (bake.id == bake_id) {
|
||||
return &bake;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void draw_bake_ui(uiLayout *layout,
|
||||
Object &object,
|
||||
NodesModifierData &nmd,
|
||||
NodesModifierBake &bake)
|
||||
{
|
||||
PointerRNA bake_ptr;
|
||||
RNA_pointer_create(&object.id, &RNA_NodesModifierBake, &bake, &bake_ptr);
|
||||
|
||||
uiLayout *settings_col = uiLayoutColumn(layout, false);
|
||||
{
|
||||
uiLayout *row = uiLayoutRow(settings_col, false);
|
||||
uiItemR(row, &bake_ptr, "bake_type", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
|
||||
}
|
||||
if (bake.bake_type == NODES_MODIFIER_BAKE_TYPE_ANIMATED) {
|
||||
uiLayout *subcol = uiLayoutColumn(settings_col, true);
|
||||
uiItemR(subcol, &bake_ptr, "frame_start", UI_ITEM_NONE, "Start", ICON_NONE);
|
||||
uiItemR(subcol, &bake_ptr, "frame_end", UI_ITEM_NONE, "End", ICON_NONE);
|
||||
}
|
||||
|
||||
uiItemR(settings_col, &bake_ptr, "directory", UI_ITEM_NONE, "", ICON_NONE);
|
||||
|
||||
uiLayout *row = uiLayoutRow(layout, true);
|
||||
{
|
||||
PointerRNA op_ptr;
|
||||
uiItemFullO(row,
|
||||
"OBJECT_OT_geometry_node_bake",
|
||||
"Bake",
|
||||
ICON_NONE,
|
||||
nullptr,
|
||||
WM_OP_INVOKE_DEFAULT,
|
||||
UI_ITEM_NONE,
|
||||
&op_ptr);
|
||||
WM_operator_properties_id_lookup_set_from_id(&op_ptr, &object.id);
|
||||
RNA_string_set(&op_ptr, "modifier", nmd.modifier.name);
|
||||
RNA_int_set(&op_ptr, "bake_id", bake.id);
|
||||
}
|
||||
{
|
||||
PointerRNA op_ptr;
|
||||
uiItemFullO(row,
|
||||
"OBJECT_OT_geometry_node_bake_delete",
|
||||
"",
|
||||
ICON_TRASH,
|
||||
nullptr,
|
||||
WM_OP_INVOKE_DEFAULT,
|
||||
UI_ITEM_NONE,
|
||||
&op_ptr);
|
||||
WM_operator_properties_id_lookup_set_from_id(&op_ptr, &object.id);
|
||||
RNA_string_set(&op_ptr, "modifier", nmd.modifier.name);
|
||||
RNA_int_set(&op_ptr, "bake_id", bake.id);
|
||||
}
|
||||
}
|
||||
|
||||
static void node_layout(uiLayout *layout, bContext *C, PointerRNA *ptr)
|
||||
{
|
||||
const bNode *node = static_cast<bNode *>(ptr->data);
|
||||
SpaceNode *snode = CTX_wm_space_node(C);
|
||||
if (snode == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (snode->id == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (GS(snode->id->name) != ID_OB) {
|
||||
return;
|
||||
}
|
||||
Object *object = reinterpret_cast<Object *>(snode->id);
|
||||
ModifierData *md = BKE_object_active_modifier(object);
|
||||
if (md == nullptr || md->type != eModifierType_Nodes) {
|
||||
return;
|
||||
}
|
||||
NodesModifierData &nmd = *reinterpret_cast<NodesModifierData *>(md);
|
||||
if (nmd.node_group != snode->nodetree) {
|
||||
return;
|
||||
}
|
||||
const std::optional<int32_t> nested_node_id = ed::space_node::find_nested_node_id_in_root(*snode,
|
||||
*node);
|
||||
if (!nested_node_id.has_value()) {
|
||||
return;
|
||||
}
|
||||
NodesModifierBake *bake = get_bake(nmd, *nested_node_id);
|
||||
if (bake == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
draw_bake_ui(layout, *object, nmd, *bake);
|
||||
}
|
||||
|
||||
static void bake_items_list_draw_item(uiList * /*ui_list*/,
|
||||
const bContext *C,
|
||||
uiLayout *layout,
|
||||
PointerRNA * /*idataptr*/,
|
||||
PointerRNA *itemptr,
|
||||
int /*icon*/,
|
||||
PointerRNA * /*active_dataptr*/,
|
||||
const char * /*active_propname*/,
|
||||
int /*index*/,
|
||||
int /*flt_flag*/)
|
||||
{
|
||||
const NodeGeometryBakeItem &item = *static_cast<NodeGeometryBakeItem *>(itemptr->data);
|
||||
|
||||
float4 color;
|
||||
const char *socket_type_idname = nodeStaticSocketType(item.socket_type, 0);
|
||||
ED_node_type_draw_color(socket_type_idname, color);
|
||||
|
||||
uiLayout *row = uiLayoutRow(layout, true);
|
||||
uiTemplateNodeSocket(row, const_cast<bContext *>(C), color);
|
||||
uiLayoutSetEmboss(layout, UI_EMBOSS_NONE);
|
||||
uiItemR(layout, itemptr, "name", UI_ITEM_NONE, "", ICON_NONE);
|
||||
}
|
||||
|
||||
static uiListType *create_items_ui_list()
|
||||
{
|
||||
uiListType *items_list = MEM_cnew<uiListType>(__func__);
|
||||
STRNCPY(items_list->idname, "NODE_UL_bake_items");
|
||||
items_list->draw_item = bake_items_list_draw_item;
|
||||
WM_uilisttype_add(items_list);
|
||||
return items_list;
|
||||
}
|
||||
|
||||
static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
|
||||
{
|
||||
static const uiListType *items_list = create_items_ui_list();
|
||||
|
||||
PointerRNA items_ptr;
|
||||
RNA_pointer_create(ptr->owner_id, &RNA_NodeGeometryBakeItems, ptr->data, &items_ptr);
|
||||
|
||||
uiLayout *list_row = uiLayoutRow(layout, false);
|
||||
uiTemplateList(list_row,
|
||||
C,
|
||||
items_list->idname,
|
||||
"",
|
||||
ptr,
|
||||
"bake_items",
|
||||
ptr,
|
||||
"active_index",
|
||||
nullptr,
|
||||
3,
|
||||
5,
|
||||
UILST_LAYOUT_DEFAULT,
|
||||
0,
|
||||
UI_TEMPLATE_LIST_FLAG_NONE);
|
||||
|
||||
{
|
||||
uiLayout *list_ops_col = uiLayoutColumn(list_row, false);
|
||||
uiLayout *add_remove_col = uiLayoutColumn(list_ops_col, true);
|
||||
|
||||
uiItemO(add_remove_col, "", ICON_ADD, "NODE_OT_bake_item_add");
|
||||
uiItemO(add_remove_col, "", ICON_REMOVE, "NODE_OT_bake_item_remove");
|
||||
|
||||
uiItemS(list_ops_col);
|
||||
|
||||
uiLayout *up_down_col = uiLayoutColumn(list_ops_col, true);
|
||||
uiItemEnumO(up_down_col, "NODE_OT_bake_item_move", "", ICON_TRIA_UP, "direction", 0);
|
||||
uiItemEnumO(up_down_col, "NODE_OT_bake_item_move", "", ICON_TRIA_DOWN, "direction", 1);
|
||||
}
|
||||
|
||||
bNode &node = *static_cast<bNode *>(ptr->data);
|
||||
NodeGeometryBake &storage = node_storage(node);
|
||||
if (storage.active_index < 0 || storage.active_index >= storage.items_num) {
|
||||
return;
|
||||
}
|
||||
NodeGeometryBakeItem &active_item = storage.items[storage.active_index];
|
||||
|
||||
PointerRNA active_item_ptr;
|
||||
RNA_pointer_create(ptr->owner_id, &RNA_NodeGeometryBakeItem, &active_item, &active_item_ptr);
|
||||
|
||||
uiItemR(layout, &active_item_ptr, "socket_type", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
if (ELEM(active_item.socket_type,
|
||||
SOCK_BOOLEAN,
|
||||
SOCK_INT,
|
||||
SOCK_FLOAT,
|
||||
SOCK_VECTOR,
|
||||
SOCK_RGBA,
|
||||
SOCK_ROTATION))
|
||||
{
|
||||
uiItemR(layout, &active_item_ptr, "attribute_domain", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
class LazyFunctionForBakeNode : public LazyFunction {
|
||||
const bNode &node_;
|
||||
bke::bake::BakeSocketConfig bake_socket_config_;
|
||||
|
||||
public:
|
||||
LazyFunctionForBakeNode(const bNode &node, GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
|
||||
: node_(node)
|
||||
{
|
||||
debug_name_ = "Bake";
|
||||
|
||||
const NodeGeometryBake &storage = node_storage(node);
|
||||
|
||||
MutableSpan<int> lf_index_by_bsocket = own_lf_graph_info.mapping.lf_index_by_bsocket;
|
||||
|
||||
bake_socket_config_.types.resize(storage.items_num);
|
||||
bake_socket_config_.domains.resize(storage.items_num);
|
||||
bake_socket_config_.geometries_by_attribute.resize(storage.items_num);
|
||||
|
||||
int last_geometry_index = -1;
|
||||
for (const int i : IndexRange(storage.items_num)) {
|
||||
const NodeGeometryBakeItem &item = storage.items[i];
|
||||
const bNodeSocket &input_bsocket = node.input_socket(i);
|
||||
const bNodeSocket &output_bsocket = node.output_socket(i);
|
||||
const CPPType &type = *input_bsocket.typeinfo->geometry_nodes_cpp_type;
|
||||
lf_index_by_bsocket[input_bsocket.index_in_tree()] = inputs_.append_and_get_index_as(
|
||||
item.name, type, lf::ValueUsage::Maybe);
|
||||
lf_index_by_bsocket[output_bsocket.index_in_tree()] = outputs_.append_and_get_index_as(
|
||||
item.name, type);
|
||||
|
||||
bake_socket_config_.types[i] = eNodeSocketDatatype(item.socket_type);
|
||||
bake_socket_config_.domains[i] = eAttrDomain(item.attribute_domain);
|
||||
|
||||
if (item.socket_type == SOCK_GEOMETRY) {
|
||||
last_geometry_index = i;
|
||||
}
|
||||
else if (last_geometry_index != -1) {
|
||||
bake_socket_config_.geometries_by_attribute[i].append(last_geometry_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void execute_impl(lf::Params ¶ms, const lf::Context &context) const final
|
||||
{
|
||||
params.set_default_remaining_outputs();
|
||||
}
|
||||
};
|
||||
|
||||
class LazyFunctionForBakeNodeInputUsage : public LazyFunction {
|
||||
const bNode &node_;
|
||||
|
||||
public:
|
||||
LazyFunctionForBakeNodeInputUsage(const bNode &node) : node_(node)
|
||||
{
|
||||
debug_name_ = "Bake Input Usage";
|
||||
/* TODO: Handle case when not all outputs are required in pass-through mode. */
|
||||
outputs_.append_as("Usage", CPPType::get<bool>());
|
||||
}
|
||||
|
||||
void execute_impl(lf::Params ¶ms, const lf::Context &context) const final
|
||||
{
|
||||
const bool inputs_required = this->bake_inputs_required(context);
|
||||
params.set_output(0, inputs_required);
|
||||
}
|
||||
|
||||
bool bake_inputs_required(const lf::Context & /*context*/) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
static void node_register()
|
||||
{
|
||||
namespace file_ns = blender::nodes::node_geo_bake_cc;
|
||||
|
||||
static bNodeType ntype;
|
||||
|
||||
geo_node_type_base(&ntype, GEO_NODE_BAKE, "Bake", NODE_CLASS_GEOMETRY);
|
||||
ntype.initfunc = file_ns::node_init;
|
||||
ntype.declare_dynamic = file_ns::node_declare_dynamic;
|
||||
ntype.draw_buttons = file_ns::node_layout;
|
||||
ntype.draw_buttons_ex = file_ns::node_layout_ex;
|
||||
ntype.insert_link = file_ns::node_insert_link;
|
||||
node_type_storage(
|
||||
&ntype, "NodeGeometryBake", file_ns::node_free_storage, file_ns::node_copy_storage);
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
NOD_REGISTER_NODE(node_register)
|
||||
|
||||
} // namespace blender::nodes::node_geo_bake_cc
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
std::unique_ptr<LazyFunction> get_bake_node_lazy_function(
|
||||
const bNode &node, GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
|
||||
{
|
||||
namespace file_ns = blender::nodes::node_geo_bake_cc;
|
||||
BLI_assert(node.type == GEO_NODE_BAKE);
|
||||
return std::make_unique<file_ns::LazyFunctionForBakeNode>(node, own_lf_graph_info);
|
||||
}
|
||||
|
||||
std::unique_ptr<LazyFunction> get_bake_node_input_usage_lazy_function(const bNode &node)
|
||||
{
|
||||
namespace file_ns = blender::nodes::node_geo_bake_cc;
|
||||
BLI_assert(node.type == GEO_NODE_BAKE);
|
||||
return std::make_unique<file_ns::LazyFunctionForBakeNodeInputUsage>(node);
|
||||
}
|
||||
|
||||
} // namespace blender::nodes
|
||||
|
||||
blender::Span<NodeGeometryBakeItem> NodeGeometryBake::items_span() const
|
||||
{
|
||||
return blender::Span<NodeGeometryBakeItem>(items, items_num);
|
||||
}
|
||||
|
||||
blender::MutableSpan<NodeGeometryBakeItem> NodeGeometryBake::items_span()
|
||||
{
|
||||
return blender::MutableSpan<NodeGeometryBakeItem>(items, items_num);
|
||||
}
|
||||
|
||||
bool NodeGeometryBakeItem::supports_type(const eNodeSocketDatatype type)
|
||||
{
|
||||
return ELEM(type,
|
||||
SOCK_FLOAT,
|
||||
SOCK_VECTOR,
|
||||
SOCK_RGBA,
|
||||
SOCK_BOOLEAN,
|
||||
SOCK_ROTATION,
|
||||
SOCK_INT,
|
||||
SOCK_GEOMETRY);
|
||||
}
|
||||
|
||||
std::string NodeGeometryBakeItem::identifier_str() const
|
||||
{
|
||||
return "Item_" + std::to_string(this->identifier);
|
||||
}
|
||||
|
||||
NodeGeometryBakeItem *NodeGeometryBake::add_item(const char *name, const eNodeSocketDatatype type)
|
||||
{
|
||||
if (!NodeGeometryBakeItem::supports_type(type)) {
|
||||
return nullptr;
|
||||
}
|
||||
const int insert_index = this->items_num;
|
||||
NodeGeometryBakeItem *old_items = this->items;
|
||||
|
||||
this->items = MEM_cnew_array<NodeGeometryBakeItem>(this->items_num + 1, __func__);
|
||||
std::copy_n(old_items, insert_index, this->items);
|
||||
NodeGeometryBakeItem &new_item = this->items[insert_index];
|
||||
std::copy_n(old_items + insert_index + 1,
|
||||
this->items_num - insert_index,
|
||||
this->items + insert_index + 1);
|
||||
|
||||
new_item.identifier = this->next_identifier++;
|
||||
this->set_item_name(new_item, name);
|
||||
new_item.socket_type = type;
|
||||
|
||||
this->items_num++;
|
||||
MEM_SAFE_FREE(old_items);
|
||||
return &new_item;
|
||||
}
|
||||
|
||||
void NodeGeometryBake::set_item_name(NodeGeometryBakeItem &item, const char *name)
|
||||
{
|
||||
char unique_name[MAX_NAME + 4];
|
||||
STRNCPY(unique_name, name);
|
||||
|
||||
struct Args {
|
||||
NodeGeometryBake *storage;
|
||||
const NodeGeometryBakeItem *item;
|
||||
} args = {this, &item};
|
||||
|
||||
const char *default_name = nodeStaticSocketLabel(item.socket_type, 0);
|
||||
BLI_uniquename_cb(
|
||||
[](void *arg, const char *name) {
|
||||
const Args &args = *static_cast<Args *>(arg);
|
||||
for (const NodeGeometryBakeItem &item : args.storage->items_span()) {
|
||||
if (&item != args.item) {
|
||||
if (STREQ(item.name, name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
&args,
|
||||
default_name,
|
||||
'.',
|
||||
unique_name,
|
||||
ARRAY_SIZE(unique_name));
|
||||
|
||||
MEM_SAFE_FREE(item.name);
|
||||
item.name = BLI_strdup(unique_name);
|
||||
}
|
@ -2730,6 +2730,10 @@ struct GeometryNodesLazyFunctionGraphBuilder {
|
||||
this->build_switch_node(bnode, graph_params);
|
||||
break;
|
||||
}
|
||||
case GEO_NODE_BAKE: {
|
||||
this->build_bake_node(bnode, graph_params);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (node_type->geometry_node_execute) {
|
||||
this->build_geometry_node(bnode, graph_params);
|
||||
@ -3286,6 +3290,46 @@ struct GeometryNodesLazyFunctionGraphBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
void build_bake_node(const bNode &bnode, BuildGraphParams &graph_params)
|
||||
{
|
||||
std::unique_ptr<LazyFunction> lazy_function = get_bake_node_lazy_function(bnode,
|
||||
*lf_graph_info_);
|
||||
lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(*lazy_function);
|
||||
scope_.add(std::move(lazy_function));
|
||||
|
||||
const NodeGeometryBake &storage = *static_cast<const NodeGeometryBake *>(bnode.storage);
|
||||
for (const int i : IndexRange(storage.items_num)) {
|
||||
{
|
||||
lf::InputSocket &lf_socket = lf_node.input(i);
|
||||
const bNodeSocket &bsocket = bnode.input_socket(i);
|
||||
graph_params.lf_inputs_by_bsocket.add(&bsocket, &lf_socket);
|
||||
mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
|
||||
}
|
||||
{
|
||||
lf::OutputSocket &lf_socket = lf_node.output(i);
|
||||
const bNodeSocket &bsocket = bnode.output_socket(i);
|
||||
graph_params.lf_output_by_bsocket.add(&bsocket, &lf_socket);
|
||||
mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
|
||||
}
|
||||
}
|
||||
|
||||
mapping_->bake_node_map.add(&bnode, &lf_node);
|
||||
|
||||
this->build_bake_node_socket_usage(bnode, graph_params);
|
||||
}
|
||||
|
||||
void build_bake_node_socket_usage(const bNode &bnode, BuildGraphParams &graph_params)
|
||||
{
|
||||
std::unique_ptr<LazyFunction> lazy_function = get_bake_node_input_usage_lazy_function(bnode);
|
||||
lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(*lazy_function);
|
||||
scope_.add(std::move(lazy_function));
|
||||
|
||||
const NodeGeometryBake &storage = *static_cast<const NodeGeometryBake *>(bnode.storage);
|
||||
for (const int i : IndexRange(storage.items_num)) {
|
||||
graph_params.usage_by_bsocket.add(&bnode.input_socket(i), &lf_node.output(0));
|
||||
}
|
||||
}
|
||||
|
||||
void build_undefined_node(const bNode &bnode, BuildGraphParams &graph_params)
|
||||
{
|
||||
auto &lazy_function = scope_.construct<LazyFunctionForUndefinedNode>(
|
||||
|
Loading…
Reference in New Issue
Block a user