Geometry Nodes: add simulation support #104924
|
@ -5,6 +5,10 @@ from bpy.types import Operator
|
|||
|
||||
from bpy.app.translations import pgettext_data as data_
|
||||
|
||||
from bpy.props import (
|
||||
EnumProperty,
|
||||
)
|
||||
|
||||
|
||||
def build_default_empty_geometry_node_group(name):
|
||||
group = bpy.data.node_groups.new(name, 'GeometryNodeTree')
|
||||
|
@ -237,8 +241,102 @@ class NewGeometryNodeTreeAssign(Operator):
|
|||
return {'FINISHED'}
|
||||
|
||||
|
||||
class SimulationZoneOperator():
|
||||
input_node_type = 'GeometryNodeSimulationInput'
|
||||
output_node_type = 'GeometryNodeSimulationOutput'
|
||||
|
||||
@classmethod
|
||||
def get_output_node(cls, context):
|
||||
node = context.active_node
|
||||
if node.bl_idname == cls.input_node_type:
|
||||
return node.paired_output
|
||||
if node.bl_idname == cls.output_node_type:
|
||||
return node
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
space = context.space_data
|
||||
# Needs active node editor and a tree.
|
||||
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 or node.bl_idname not in [cls.input_node_type, cls.output_node_type]:
|
||||
return False
|
||||
if cls.get_output_node(context) is None:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class SimulationZoneItemAddOperator(SimulationZoneOperator, Operator):
|
||||
'''Add a state item to the simulation zone'''
|
||||
bl_idname = "node.simulation_zone_item_add"
|
||||
bl_label = "Add State Item"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
default_socket_type = 'GEOMETRY'
|
||||
|
||||
def execute(self, context):
|
||||
node = self.get_output_node(context)
|
||||
state_items = node.state_items
|
||||
|
||||
# Remember index to move the item.
|
||||
dst_index = min(node.active_index + 1, len(state_items))
|
||||
# Empty name so it is based on the type only.
|
||||
state_items.new(self.default_socket_type, "")
|
||||
state_items.move(len(state_items) - 1, dst_index)
|
||||
node.active_index = dst_index
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class SimulationZoneItemRemoveOperator(SimulationZoneOperator, Operator):
|
||||
'''Remove a state item from the simulation zone'''
|
||||
bl_idname = "node.simulation_zone_item_remove"
|
||||
bl_label = "Remove State Item"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
def execute(self, context):
|
||||
node = self.get_output_node(context)
|
||||
state_items = node.state_items
|
||||
|
||||
if node.active_item:
|
||||
state_items.remove(node.active_item)
|
||||
node.active_index = min(node.active_index, len(state_items) - 1)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class SimulationZoneItemMoveOperator(SimulationZoneOperator, Operator):
|
||||
'''Move a simulation state item up or down in the list'''
|
||||
bl_idname = "node.simulation_zone_item_move"
|
||||
bl_label = "Move State Item"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
direction: EnumProperty(
|
||||
name="Direction",
|
||||
items=[('UP', "Up", ""), ('DOWN', "Down", "")],
|
||||
default = 'UP',
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
node = self.get_output_node(context)
|
||||
state_items = node.state_items
|
||||
|
||||
if self.direction == 'UP' and node.active_index > 0:
|
||||
state_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(state_items) - 1:
|
||||
state_items.move(node.active_index, node.active_index + 1)
|
||||
node.active_index = node.active_index + 1
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
classes = (
|
||||
NewGeometryNodesModifier,
|
||||
NewGeometryNodeTreeAssign,
|
||||
MoveModifierToNodes,
|
||||
SimulationZoneItemAddOperator,
|
||||
SimulationZoneItemRemoveOperator,
|
||||
SimulationZoneItemMoveOperator,
|
||||
)
|
||||
|
|
|
@ -954,6 +954,76 @@ class NODE_PT_node_tree_interface_outputs(NodeTreeInterfacePanel):
|
|||
self.draw_socket_list(context, "OUT", "outputs", "active_output")
|
||||
|
||||
|
||||
class NODE_UL_simulation_zone_items(bpy.types.UIList):
|
||||
def draw_item(self, context, layout, _data, item, icon, _active_data, _active_propname, _index):
|
||||
if self.layout_type in {'DEFAULT', 'COMPACT'}:
|
||||
row = layout.row(align=True)
|
||||
|
||||
row.template_node_socket(color=item.color)
|
||||
row.prop(item, "name", text="", emboss=False, icon_value=icon)
|
||||
elif self.layout_type == 'GRID':
|
||||
layout.alignment = 'CENTER'
|
||||
layout.template_node_socket(color=item.color)
|
||||
|
||||
|
||||
class NODE_PT_simulation_zone_items(Panel):
|
||||
bl_space_type = 'NODE_EDITOR'
|
||||
bl_region_type = 'UI'
|
||||
bl_category = "Node"
|
||||
bl_label = "Simulation State"
|
||||
|
||||
input_node_type = 'GeometryNodeSimulationInput'
|
||||
output_node_type = 'GeometryNodeSimulationOutput'
|
||||
|
||||
@classmethod
|
||||
def get_output_node(cls, context):
|
||||
node = context.active_node
|
||||
if node.bl_idname == cls.input_node_type:
|
||||
return node.paired_output
|
||||
if node.bl_idname == cls.output_node_type:
|
||||
return node
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
snode = context.space_data
|
||||
if snode is None:
|
||||
return False
|
||||
node = context.active_node
|
||||
if node is None or node.bl_idname not in [cls.input_node_type, cls.output_node_type]:
|
||||
return False
|
||||
if cls.get_output_node(context) is None:
|
||||
return False
|
||||
return True
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
output_node = self.get_output_node(context)
|
||||
|
||||
split = layout.row()
|
||||
|
||||
split.template_list("NODE_UL_simulation_zone_items", "", output_node, "state_items", output_node, "active_index")
|
||||
|
||||
ops_col = split.column()
|
||||
|
||||
add_remove_col = ops_col.column(align=True)
|
||||
add_remove_col.operator("node.simulation_zone_item_add", icon='ADD', text="")
|
||||
add_remove_col.operator("node.simulation_zone_item_remove", icon='REMOVE', text="")
|
||||
|
||||
ops_col.separator()
|
||||
|
||||
up_down_col = ops_col.column(align=True)
|
||||
props = up_down_col.operator("node.simulation_zone_item_move", icon='TRIA_UP', text="")
|
||||
props.direction = 'UP'
|
||||
props = up_down_col.operator("node.simulation_zone_item_move", icon='TRIA_DOWN', text="")
|
||||
props.direction = 'DOWN'
|
||||
|
||||
active_item = output_node.active_item
|
||||
if active_item is not None:
|
||||
layout.prop(active_item, "socket_type")
|
||||
layout.prop(active_item, "name")
|
||||
|
||||
|
||||
# Grease Pencil properties
|
||||
class NODE_PT_annotation(AnnotationDataPanel, Panel):
|
||||
bl_space_type = 'NODE_EDITOR'
|
||||
|
@ -1018,6 +1088,8 @@ classes = (
|
|||
NODE_UL_interface_sockets,
|
||||
NODE_PT_node_tree_interface_inputs,
|
||||
NODE_PT_node_tree_interface_outputs,
|
||||
NODE_UL_simulation_zone_items,
|
||||
NODE_PT_simulation_zone_items,
|
||||
|
||||
node_panel(EEVEE_MATERIAL_PT_settings),
|
||||
node_panel(MATERIAL_PT_viewport),
|
||||
|
|
|
@ -572,6 +572,15 @@ class NodeTreeMainUpdater {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
/* Check paired simulation zone nodes. */
|
||||
if (node.type == GEO_NODE_SIMULATION_INPUT) {
|
||||
const NodeGeometrySimulationInput *data = static_cast<const NodeGeometrySimulationInput *>(node.storage);
|
||||
if (const bNode *output_node = ntree.node_by_id(data->output_node_id)) {
|
||||
if (output_node->runtime->changed_flag & NTREE_CHANGED_NODE_PROPERTY) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -4308,6 +4308,70 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
|
||||
/* Rename Grease Pencil weight draw brush. */
|
||||
do_versions_rename_id(bmain, ID_BR, "Draw Weight", "Weight Draw");
|
||||
|
||||
/* Identifier generation for simulation node sockets changed.
|
||||
* Update identifiers so links are not removed during validation. */
|
||||
if (!DNA_struct_elem_find(fd->filesdna, "NodeSimulationItem", "int", "identifier")) {
|
||||
static auto set_socket_identifiers = [](bNode *node, const bNode *output_node, int extra_outputs) {
|
||||
const NodeGeometrySimulationOutput *output_data = static_cast<const NodeGeometrySimulationOutput *>(output_node->storage);
|
||||
/* Includes extension socket. */
|
||||
BLI_assert(BLI_listbase_count(&node->inputs) == output_data->items_num + 1);
|
||||
/* Includes extension socket. */
|
||||
BLI_assert(BLI_listbase_count(&node->outputs) == output_data->items_num + 1 + extra_outputs);
|
||||
|
||||
int i;
|
||||
LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->inputs, i) {
|
||||
/* Skip extension socket. */
|
||||
if (i >= output_data->items_num) {
|
||||
break;
|
||||
}
|
||||
BLI_snprintf(sock->identifier, sizeof(sock->identifier), "Item_%d", output_data->items[i].identifier);
|
||||
}
|
||||
LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->outputs, i) {
|
||||
const int item_i = i - extra_outputs;
|
||||
/* Skip extra outputs. */
|
||||
if (i < extra_outputs) {
|
||||
continue;
|
||||
}
|
||||
/* Skip extension socket. */
|
||||
if (item_i >= output_data->items_num) {
|
||||
break;
|
||||
}
|
||||
BLI_snprintf(sock->identifier, sizeof(sock->identifier), "Item_%d", output_data->items[i - extra_outputs].identifier);
|
||||
}
|
||||
};
|
||||
|
||||
LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
|
||||
if (ntree->type == NTREE_GEOMETRY) {
|
||||
/* Initialize item identifiers. */
|
||||
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
|
||||
if (node->type == GEO_NODE_SIMULATION_OUTPUT) {
|
||||
NodeGeometrySimulationOutput *data = static_cast<NodeGeometrySimulationOutput *>(node->storage);
|
||||
for (int i = 0; i < data->items_num; ++i) {
|
||||
data->items[i].identifier = i;
|
||||
}
|
||||
data->next_identifier = data->items_num;
|
||||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
|
||||
if (node->type == GEO_NODE_SIMULATION_INPUT) {
|
||||
const NodeGeometrySimulationInput *input_data = static_cast<const NodeGeometrySimulationInput *>(node->storage);
|
||||
LISTBASE_FOREACH (bNode *, output_node, &ntree->nodes) {
|
||||
if (output_node->identifier == input_data->output_node_id) {
|
||||
/* 'Delta Time' socket in input nodes */
|
||||
set_socket_identifiers(node, output_node, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node->type == GEO_NODE_SIMULATION_OUTPUT) {
|
||||
set_socket_identifiers(node, node, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -73,6 +73,7 @@ void ED_init_node_socket_type_virtual(struct bNodeSocketType *stype);
|
|||
void ED_node_sample_set(const float col[4]);
|
||||
void ED_node_draw_snap(
|
||||
struct View2D *v2d, const float cent[2], float size, NodeBorder border, unsigned int pos);
|
||||
void ED_node_type_draw_color(const char *idname, float *r_color);
|
||||
|
||||
/* node_draw.cc */
|
||||
|
||||
|
|
|
@ -1497,6 +1497,23 @@ void ED_init_node_socket_type_virtual(bNodeSocketType *stype)
|
|||
stype->draw_color = node_socket_virtual_draw_color;
|
||||
}
|
||||
|
||||
void ED_node_type_draw_color(const char *idname, float *r_color)
|
||||
{
|
||||
using namespace blender::ed::space_node;
|
||||
|
||||
const bNodeSocketType *typeinfo = nodeSocketTypeFind(idname);
|
||||
if (!typeinfo || typeinfo->type == SOCK_CUSTOM) {
|
||||
r_color[0] = 0.0f;
|
||||
r_color[1] = 0.0f;
|
||||
r_color[2] = 0.0f;
|
||||
r_color[3] = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
BLI_assert(typeinfo->type < ARRAY_SIZE(std_node_socket_colors));
|
||||
copy_v4_v4(r_color, std_node_socket_colors[typeinfo->type]);
|
||||
}
|
||||
|
||||
namespace blender::ed::space_node {
|
||||
|
||||
/* ************** Generic drawing ************** */
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#ifdef __cplusplus
|
||||
namespace blender {
|
||||
template<typename T> class Span;
|
||||
template<typename T> class MutableSpan;
|
||||
class IndexRange;
|
||||
class StringRef;
|
||||
class StringRefNull;
|
||||
} // namespace blender
|
||||
|
@ -1600,7 +1602,9 @@ typedef struct NodeSimulationItem {
|
|||
/* #eNodeSocketDatatype. */
|
||||
/* TODO: Use a different enum instead to support Byte colors, etc. */
|
||||
short socket_type;
|
||||
char _pad[6];
|
||||
short _pad;
|
||||
/* Generates unique identifier for sockets. */
|
||||
int identifier;
|
||||
} NodeSimulationItem;
|
||||
|
||||
typedef struct NodeGeometrySimulationInput {
|
||||
|
@ -1610,7 +1614,16 @@ typedef struct NodeGeometrySimulationInput {
|
|||
typedef struct NodeGeometrySimulationOutput {
|
||||
NodeSimulationItem *items;
|
||||
int items_num;
|
||||
char _pad[4];
|
||||
int active_index;
|
||||
/* Number to give unique IDs to state items. */
|
||||
int next_identifier;
|
||||
int _pad;
|
||||
|
||||
#ifdef __cplusplus
|
||||
blender::Span<NodeSimulationItem> items_span() const;
|
||||
blender::MutableSpan<NodeSimulationItem> items_span_for_write();
|
||||
blender::IndexRange items_range() const;
|
||||
#endif
|
||||
} NodeGeometrySimulationOutput;
|
||||
|
||||
typedef struct NodeGeometryDistributePointsInVolume {
|
||||
|
|
|
@ -52,6 +52,8 @@
|
|||
#include "RE_texture.h"
|
||||
|
||||
#include "NOD_composite.h"
|
||||
#include "NOD_geometry.h"
|
||||
#include "NOD_socket.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
@ -4087,6 +4089,60 @@ static void rna_NodeCryptomatte_update_remove(Main *bmain, Scene *scene, Pointer
|
|||
rna_Node_update(bmain, scene, ptr);
|
||||
}
|
||||
|
||||
static void rna_SimulationStateItem_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
|
||||
{
|
||||
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
|
||||
NodeSimulationItem *item = (NodeSimulationItem *)ptr->data;
|
||||
bNode *node = NOD_geometry_simulation_output_find_node_by_item(ntree, item);
|
||||
|
||||
BKE_ntree_update_tag_node_property(ntree, node);
|
||||
ED_node_tree_propagate_change(NULL, bmain, ntree);
|
||||
}
|
||||
|
||||
static bool rna_SimulationStateItem_socket_type_supported(const EnumPropertyItem *item)
|
||||
{
|
||||
return NOD_geometry_simulation_output_item_socket_type_supported((eNodeSocketDatatype)item->value);
|
||||
}
|
||||
|
||||
static const EnumPropertyItem *rna_SimulationStateItem_socket_type_itemf(bContext *UNUSED(C),
|
||||
PointerRNA *UNUSED(ptr),
|
||||
PropertyRNA *UNUSED(prop),
|
||||
bool *r_free)
|
||||
{
|
||||
*r_free = true;
|
||||
return itemf_function_check(node_socket_data_type_items, rna_SimulationStateItem_socket_type_supported);
|
||||
}
|
||||
|
||||
static void rna_SimulationStateItem_name_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
|
||||
NodeSimulationItem *item = (NodeSimulationItem *)ptr->data;
|
||||
bNode *node = NOD_geometry_simulation_output_find_node_by_item(ntree, item);
|
||||
NodeGeometrySimulationOutput *sim = (NodeGeometrySimulationOutput *)node->storage;
|
||||
|
||||
const char *defname = nodeStaticSocketLabel(item->socket_type, 0);
|
||||
NOD_geometry_simulation_output_item_set_unique_name(sim, item, value, defname);
|
||||
}
|
||||
|
||||
static void rna_SimulationStateItem_color_get(PointerRNA *ptr, float *values)
|
||||
{
|
||||
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
|
||||
NodeSimulationItem *item = (NodeSimulationItem *)ptr->data;
|
||||
|
||||
const char *socket_type_idname = nodeStaticSocketType(item->socket_type, 0);
|
||||
node_type_draw_color(socket_type_idname, values);
|
||||
}
|
||||
|
||||
static PointerRNA rna_NodeGeometrySimulationInput_paired_output_get(PointerRNA *ptr)
|
||||
{
|
||||
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
|
||||
bNode *node = (bNode *)ptr->data;
|
||||
bNode *output_node = NOD_geometry_simulation_input_get_paired_output(ntree, node);
|
||||
PointerRNA r_ptr;
|
||||
RNA_pointer_create(&ntree->id, &RNA_Node, output_node, &r_ptr);
|
||||
return r_ptr;
|
||||
}
|
||||
|
||||
static bool rna_GeometryNodeSimulationInput_pair_with_output(
|
||||
ID *id, bNode *node, bContext *C, ReportList *reports, bNode *output_node)
|
||||
{
|
||||
|
@ -4108,6 +4164,100 @@ static bool rna_GeometryNodeSimulationInput_pair_with_output(
|
|||
return true;
|
||||
}
|
||||
|
||||
static NodeSimulationItem *rna_NodeGeometrySimulationOutput_items_new(
|
||||
ID *id,
|
||||
bNode *node,
|
||||
Main *bmain,
|
||||
ReportList *reports,
|
||||
int socket_type,
|
||||
const char *name)
|
||||
{
|
||||
NodeGeometrySimulationOutput *sim = (NodeGeometrySimulationOutput *)node->storage;
|
||||
NodeSimulationItem *item = NOD_geometry_simulation_output_add_item(sim, (short)socket_type, name);
|
||||
|
||||
if (item == NULL) {
|
||||
BKE_report(reports, RPT_ERROR, "Unable to create socket");
|
||||
}
|
||||
else {
|
||||
bNodeTree *ntree = (bNodeTree *)id;
|
||||
BKE_ntree_update_tag_node_property(ntree, node);
|
||||
ED_node_tree_propagate_change(NULL, 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)
|
||||
{
|
||||
NodeGeometrySimulationOutput *sim = (NodeGeometrySimulationOutput *)node->storage;
|
||||
if (!NOD_geometry_simulation_output_contains_item(sim, item)) {
|
||||
BKE_reportf(reports, RPT_ERROR, "Unable to locate item '%s' in node", item->name);
|
||||
}
|
||||
else {
|
||||
NOD_geometry_simulation_output_remove_item(sim, item);
|
||||
|
||||
bNodeTree *ntree = (bNodeTree *)id;
|
||||
BKE_ntree_update_tag_node_property(ntree, node);
|
||||
ED_node_tree_propagate_change(NULL, 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 = (NodeGeometrySimulationOutput *)node->storage;
|
||||
NOD_geometry_simulation_output_clear_items(sim);
|
||||
|
||||
bNodeTree *ntree = (bNodeTree *)id;
|
||||
BKE_ntree_update_tag_node_property(ntree, node);
|
||||
ED_node_tree_propagate_change(NULL, bmain, ntree);
|
||||
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
|
||||
}
|
||||
|
||||
static void rna_NodeGeometrySimulationOutput_items_move(ID *id,
|
||||
bNode *node,
|
||||
Main *bmain,
|
||||
int from_index,
|
||||
int to_index)
|
||||
{
|
||||
NodeGeometrySimulationOutput *sim = (NodeGeometrySimulationOutput *)node->storage;
|
||||
|
||||
if (from_index < 0 || from_index >= sim->items_num || to_index < 0 || to_index >= sim->items_num) {
|
||||
return;
|
||||
}
|
||||
|
||||
NOD_geometry_simulation_output_move_item(sim, from_index, to_index);
|
||||
|
||||
bNodeTree *ntree = (bNodeTree *)id;
|
||||
BKE_ntree_update_tag_node_property(ntree, node);
|
||||
ED_node_tree_propagate_change(NULL, bmain, ntree);
|
||||
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
|
||||
}
|
||||
|
||||
static PointerRNA rna_NodeGeometrySimulationOutput_active_item_get(PointerRNA *ptr)
|
||||
{
|
||||
bNode *node = (bNode *)ptr->data;
|
||||
NodeGeometrySimulationOutput *sim = (NodeGeometrySimulationOutput *)node->storage;
|
||||
NodeSimulationItem *item = NOD_geometry_simulation_output_get_active_item(sim);
|
||||
PointerRNA r_ptr;
|
||||
RNA_pointer_create(ptr->owner_id, &RNA_SimulationStateItem, item, &r_ptr);
|
||||
return r_ptr;
|
||||
}
|
||||
|
||||
static void rna_NodeGeometrySimulationOutput_active_item_set(PointerRNA *ptr, PointerRNA value)
|
||||
{
|
||||
bNode *node = (bNode *)ptr->data;
|
||||
NodeGeometrySimulationOutput *sim = (NodeGeometrySimulationOutput *)node->storage;
|
||||
NOD_geometry_simulation_output_set_active_item(sim, (NodeSimulationItem *)value.data);
|
||||
}
|
||||
|
||||
/* ******** Node Socket Types ******** */
|
||||
|
||||
static PointerRNA rna_NodeOutputFile_slot_layer_get(CollectionPropertyIterator *iter)
|
||||
|
@ -9759,9 +9909,19 @@ static void def_geo_set_curve_normal(StructRNA *srna)
|
|||
|
||||
static void def_geo_simulation_input(StructRNA *srna)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
FunctionRNA *func;
|
||||
PropertyRNA *parm;
|
||||
|
||||
RNA_def_struct_sdna_from(srna, "NodeGeometrySimulationInput", "storage");
|
||||
|
||||
prop = RNA_def_property(srna, "paired_output", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "Node");
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_pointer_funcs(
|
||||
prop, "rna_NodeGeometrySimulationInput_paired_output_get", NULL, NULL, NULL);
|
||||
RNA_def_property_ui_text(prop, "Paired Output", "Simulation output node that this input node is paired with");
|
||||
|
||||
func = RNA_def_function(
|
||||
srna, "pair_with_output", "rna_GeometryNodeSimulationInput_pair_with_output");
|
||||
RNA_def_function_ui_description(func, "Pair a simulation input node with an output node.");
|
||||
|
@ -9777,16 +9937,71 @@ static void def_geo_simulation_input(StructRNA *srna)
|
|||
|
||||
static void rna_def_simulation_state_item(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna = RNA_def_struct(brna, "SimulationStateItem", NULL);
|
||||
RNA_def_struct_ui_text(srna, "Simulation Sate Item", "");
|
||||
RNA_def_struct_sdna(srna, "NodeSimulationItem");
|
||||
|
||||
PropertyRNA *prop;
|
||||
|
||||
StructRNA *srna = RNA_def_struct(brna, "SimulationStateItem", NULL);
|
||||
RNA_def_struct_ui_text(srna, "Simulation Item", "");
|
||||
RNA_def_struct_sdna(srna, "NodeSimulationItem");
|
||||
|
||||
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SimulationStateItem_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_NodeSocket_update");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_SimulationStateItem_update");
|
||||
|
||||
prop = RNA_def_property(srna, "socket_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, node_socket_data_type_items);
|
||||
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_SimulationStateItem_socket_type_itemf");
|
||||
RNA_def_property_ui_text(prop, "Socket Type", "");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_SimulationStateItem_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_SimulationStateItem_color_get", NULL, NULL);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(prop, "Color", "Socket color");
|
||||
}
|
||||
|
||||
static void rna_def_geo_simulation_output_items(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *parm;
|
||||
FunctionRNA *func;
|
||||
|
||||
srna = RNA_def_struct(brna, "NodeGeometrySimulationOutputItems", NULL);
|
||||
RNA_def_struct_sdna(srna, "bNode");
|
||||
RNA_def_struct_ui_text(srna, "Items", "Collection of simulation items");
|
||||
|
||||
func = RNA_def_function(srna, "new", "rna_NodeGeometrySimulationOutput_items_new");
|
||||
RNA_def_function_ui_description(func, "Add a item to this simulation zone");
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
|
||||
parm = RNA_def_enum(func, "socket_type", node_socket_data_type_items, SOCK_GEOMETRY, "Socket Type", "Socket type of the item");
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
|
||||
parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
|
||||
/* return value */
|
||||
parm = RNA_def_pointer(func, "item", "SimulationStateItem", "Item", "New item");
|
||||
RNA_def_function_return(func, parm);
|
||||
|
||||
func = RNA_def_function(srna, "remove", "rna_NodeGeometrySimulationOutput_items_remove");
|
||||
RNA_def_function_ui_description(func, "Remove an item from this simulation zone");
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
|
||||
parm = RNA_def_pointer(func, "item", "SimulationStateItem", "Item", "The item to remove");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
|
||||
|
||||
func = RNA_def_function(srna, "clear", "rna_NodeGeometrySimulationOutput_items_clear");
|
||||
RNA_def_function_ui_description(func, "Remove all items from this simulation zone");
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
|
||||
|
||||
func = RNA_def_function(srna, "move", "rna_NodeGeometrySimulationOutput_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, 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, 0, PARM_REQUIRED);
|
||||
}
|
||||
|
||||
static void def_geo_simulation_output(StructRNA *srna)
|
||||
|
@ -9798,7 +10013,24 @@ static void def_geo_simulation_output(StructRNA *srna)
|
|||
prop = RNA_def_property(srna, "state_items", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_collection_sdna(prop, NULL, "items", "items_num");
|
||||
RNA_def_property_struct_type(prop, "SimulationStateItem");
|
||||
RNA_def_property_ui_text(prop, "Inputs", "");
|
||||
RNA_def_property_ui_text(prop, "Items", "");
|
||||
RNA_def_property_srna(prop, "NodeGeometrySimulationOutputItems");
|
||||
|
||||
prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_int_sdna(prop, NULL, "active_index");
|
||||
RNA_def_property_ui_text(prop, "Active Item Index", "Index of the active item");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_NODE, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "active_item", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "SimulationStateItem");
|
||||
RNA_def_property_pointer_funcs(prop,
|
||||
"rna_NodeGeometrySimulationOutput_active_item_get",
|
||||
"rna_NodeGeometrySimulationOutput_active_item_set",
|
||||
NULL,
|
||||
NULL);
|
||||
RNA_def_property_ui_text(prop, "Active Item Index", "Index of the active item");
|
||||
RNA_def_property_update(prop, NC_NODE, NULL);
|
||||
}
|
||||
|
||||
static void def_geo_curve_handle_type_selection(StructRNA *srna)
|
||||
|
@ -13222,6 +13454,7 @@ void RNA_def_nodetree(BlenderRNA *brna)
|
|||
/* special socket types */
|
||||
rna_def_cmp_output_file_slot_file(brna);
|
||||
rna_def_cmp_output_file_slot_layer(brna);
|
||||
rna_def_geo_simulation_output_items(brna);
|
||||
|
||||
rna_def_node_instance_hash(brna);
|
||||
}
|
||||
|
|
|
@ -13,16 +13,70 @@ extern struct bNodeTreeType *ntreeType_Geometry;
|
|||
void register_node_type_geo_custom_group(bNodeType *ntype);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Simulation Node API
|
||||
/** \name Simulation Input Node
|
||||
* \{ */
|
||||
|
||||
struct bNode *NOD_geometry_simulation_input_get_paired_output(
|
||||
struct bNodeTree *node_tree, const struct bNode *simulation_input_node);
|
||||
|
||||
/**
|
||||
* Pair a simulation input node with an output node.
|
||||
* \return True if pairing the node was successful.
|
||||
*/
|
||||
bool NOD_geometry_simulation_input_pair_with_output(const struct bNodeTree *node_tree,
|
||||
struct bNode *sim_input_node,
|
||||
const struct bNode *sim_output_node);
|
||||
struct bNode *simulation_input_node,
|
||||
const struct bNode *simulation_output_node);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Simulation Output Node
|
||||
* \{ */
|
||||
|
||||
bool NOD_geometry_simulation_output_item_socket_type_supported(eNodeSocketDatatype socket_type);
|
||||
|
||||
/**
|
||||
* Set a unique item name.
|
||||
* \return True if the unique name differs from the original name.
|
||||
*/
|
||||
bool NOD_geometry_simulation_output_item_set_unique_name(struct NodeGeometrySimulationOutput *sim,
|
||||
struct NodeSimulationItem *item,
|
||||
const char *name,
|
||||
const char *defname);
|
||||
|
||||
/**
|
||||
* Find the node owning this simulation state item.
|
||||
*/
|
||||
bNode *NOD_geometry_simulation_output_find_node_by_item(struct bNodeTree *ntree,
|
||||
const struct NodeSimulationItem *item);
|
||||
|
||||
bool NOD_geometry_simulation_output_contains_item(struct NodeGeometrySimulationOutput *sim,
|
||||
const struct NodeSimulationItem *item);
|
||||
struct NodeSimulationItem *NOD_geometry_simulation_output_get_active_item(
|
||||
struct NodeGeometrySimulationOutput *sim);
|
||||
void NOD_geometry_simulation_output_set_active_item(struct NodeGeometrySimulationOutput *sim,
|
||||
struct NodeSimulationItem *item);
|
||||
struct NodeSimulationItem *NOD_geometry_simulation_output_find_item(
|
||||
struct NodeGeometrySimulationOutput *sim, const char *name);
|
||||
struct NodeSimulationItem *NOD_geometry_simulation_output_add_item(
|
||||
struct NodeGeometrySimulationOutput *sim, short socket_type, const char *name);
|
||||
struct NodeSimulationItem *NOD_geometry_simulation_output_insert_item(
|
||||
struct NodeGeometrySimulationOutput *sim, short socket_type, const char *name, int index);
|
||||
struct NodeSimulationItem *NOD_geometry_simulation_output_add_item_from_socket(
|
||||
struct NodeGeometrySimulationOutput *sim,
|
||||
const struct bNode *from_node,
|
||||
const struct bNodeSocket *from_sock);
|
||||
struct NodeSimulationItem *NOD_geometry_simulation_output_insert_item_from_socket(
|
||||
struct NodeGeometrySimulationOutput *sim,
|
||||
const struct bNode *from_node,
|
||||
const struct bNodeSocket *from_sock,
|
||||
int index);
|
||||
void NOD_geometry_simulation_output_remove_item(struct NodeGeometrySimulationOutput *sim,
|
||||
struct NodeSimulationItem *item);
|
||||
void NOD_geometry_simulation_output_clear_items(struct NodeGeometrySimulationOutput *sim);
|
||||
void NOD_geometry_simulation_output_move_item(struct NodeGeometrySimulationOutput *sim,
|
||||
int from_index,
|
||||
int to_index);
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@ struct bNodeTree;
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
void node_type_draw_color(const char *idname, float *r_color);
|
||||
|
||||
struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree,
|
||||
struct bNode *node,
|
||||
struct bNodeSocketTemplate *stemp,
|
||||
|
|
|
@ -136,8 +136,5 @@ class FieldAtIndexInput final : public bke::GeometryFieldInput {
|
|||
void socket_declarations_for_simulation_items(Span<NodeSimulationItem> items,
|
||||
NodeDeclaration &r_declaration);
|
||||
const CPPType &get_simulation_item_cpp_type(const NodeSimulationItem &item);
|
||||
/** \warning Return value will be reallocated when items are added or removed. */
|
||||
NodeSimulationItem *simulation_item_add_from_socket(NodeGeometrySimulationOutput &storage,
|
||||
const bNodeSocket &socket);
|
||||
|
||||
} // namespace blender::nodes
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "UI_interface.h"
|
||||
#include "UI_resources.h"
|
||||
|
||||
#include "NOD_geometry.h"
|
||||
#include "NOD_socket.h"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
@ -142,8 +143,8 @@ static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
|
|||
|
||||
if (link->tonode == node) {
|
||||
if (link->tosock->identifier == StringRef("__extend__")) {
|
||||
if (const NodeSimulationItem *item = simulation_item_add_from_socket(storage,
|
||||
*link->fromsock)) {
|
||||
if (const NodeSimulationItem *item = NOD_geometry_simulation_output_add_item_from_socket(
|
||||
&storage, link->fromnode, link->fromsock)) {
|
||||
update_node_declaration_and_sockets(*ntree, *node);
|
||||
link->tosock = nodeFindSocket(node, SOCK_IN, item->name);
|
||||
}
|
||||
|
@ -155,8 +156,8 @@ static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
|
|||
else {
|
||||
BLI_assert(link->fromnode == node);
|
||||
if (link->fromsock->identifier == StringRef("__extend__")) {
|
||||
if (const NodeSimulationItem *item = simulation_item_add_from_socket(storage,
|
||||
*link->tosock)) {
|
||||
if (const NodeSimulationItem *item = NOD_geometry_simulation_output_add_item_from_socket(
|
||||
&storage, link->tonode, link->tosock)) {
|
||||
update_node_declaration_and_sockets(*ntree, *node);
|
||||
link->fromsock = nodeFindSocket(node, SOCK_OUT, item->name);
|
||||
}
|
||||
|
@ -186,6 +187,15 @@ void register_node_type_geo_simulation_input()
|
|||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
||||
bNode *NOD_geometry_simulation_input_get_paired_output(bNodeTree *node_tree,
|
||||
const bNode *simulation_input_node)
|
||||
{
|
||||
namespace file_ns = blender::nodes::node_geo_simulation_input_cc;
|
||||
|
||||
const NodeGeometrySimulationInput &data = file_ns::node_storage(*simulation_input_node);
|
||||
return node_tree->node_by_id(data.output_node_id);
|
||||
}
|
||||
|
||||
bool NOD_geometry_simulation_input_pair_with_output(const bNodeTree *node_tree,
|
||||
bNode *sim_input_node,
|
||||
const bNode *sim_output_node)
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
#include "UI_resources.h"
|
||||
|
||||
#include "NOD_common.h"
|
||||
#include "NOD_socket.h"
|
||||
|
@ -25,15 +24,15 @@ void socket_declarations_for_simulation_items(const Span<NodeSimulationItem> ite
|
|||
case SOCK_GEOMETRY: {
|
||||
{
|
||||
std::unique_ptr<decl::Geometry> decl = std::make_unique<decl::Geometry>();
|
||||
decl->name = item.name;
|
||||
decl->identifier = item.name;
|
||||
decl->name = item.name ? item.name : "";
|
||||
decl->identifier = "Item_" + std::to_string(item.identifier);
|
||||
decl->in_out = SOCK_IN;
|
||||
r_declaration.inputs.append(std::move(decl));
|
||||
}
|
||||
{
|
||||
std::unique_ptr<decl::Geometry> decl = std::make_unique<decl::Geometry>();
|
||||
decl->name = item.name;
|
||||
decl->identifier = item.name;
|
||||
decl->name = item.name ? item.name : "";
|
||||
decl->identifier = "Item_" + std::to_string(item.identifier);
|
||||
decl->in_out = SOCK_OUT;
|
||||
r_declaration.outputs.append(std::move(decl));
|
||||
}
|
||||
|
@ -47,13 +46,20 @@ void socket_declarations_for_simulation_items(const Span<NodeSimulationItem> ite
|
|||
r_declaration.outputs.append(decl::create_extend_declaration(SOCK_OUT));
|
||||
}
|
||||
|
||||
struct SimulationItemsUniqueNameArgs {
|
||||
NodeGeometrySimulationOutput *sim;
|
||||
const NodeSimulationItem *item;
|
||||
};
|
||||
|
||||
static bool simulation_items_unique_name_check(void *arg, const char *name)
|
||||
{
|
||||
const NodeGeometrySimulationOutput &storage = *static_cast<const NodeGeometrySimulationOutput *>(
|
||||
const SimulationItemsUniqueNameArgs &args = *static_cast<const SimulationItemsUniqueNameArgs *>(
|
||||
arg);
|
||||
for (const NodeSimulationItem &item : Span(storage.items, storage.items_num)) {
|
||||
if (STREQ(item.name, name)) {
|
||||
return true;
|
||||
for (const NodeSimulationItem &item : args.sim->items_span()) {
|
||||
if (&item != args.item) {
|
||||
if (STREQ(item.name, name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (STREQ(name, "Delta Time")) {
|
||||
|
@ -62,37 +68,6 @@ static bool simulation_items_unique_name_check(void *arg, const char *name)
|
|||
return false;
|
||||
}
|
||||
|
||||
NodeSimulationItem *simulation_item_add_from_socket(NodeGeometrySimulationOutput &storage,
|
||||
const bNodeSocket &socket)
|
||||
{
|
||||
if (socket.type != SOCK_GEOMETRY) {
|
||||
return nullptr;
|
||||
}
|
||||
char unique_name[MAX_NAME + 4] = "";
|
||||
BLI_uniquename_cb(simulation_items_unique_name_check,
|
||||
&storage,
|
||||
socket.name,
|
||||
'.',
|
||||
unique_name,
|
||||
ARRAY_SIZE(unique_name));
|
||||
|
||||
NodeSimulationItem *old_items = storage.items;
|
||||
storage.items = MEM_cnew_array<NodeSimulationItem>(storage.items_num + 1, __func__);
|
||||
for (const int i : IndexRange(storage.items_num)) {
|
||||
storage.items[i].name = old_items[i].name;
|
||||
storage.items[i].socket_type = old_items[i].socket_type;
|
||||
}
|
||||
|
||||
NodeSimulationItem &added_item = storage.items[storage.items_num];
|
||||
added_item.name = BLI_strdup(unique_name);
|
||||
added_item.socket_type = socket.type;
|
||||
|
||||
storage.items_num++;
|
||||
MEM_SAFE_FREE(old_items);
|
||||
|
||||
return &added_item;
|
||||
}
|
||||
|
||||
const CPPType &get_simulation_item_cpp_type(const NodeSimulationItem &item)
|
||||
{
|
||||
switch (item.socket_type) {
|
||||
|
@ -273,10 +248,15 @@ static void node_declare_dynamic(const bNodeTree & /*node_tree*/,
|
|||
static void node_init(bNodeTree * /*tree*/, bNode *node)
|
||||
{
|
||||
NodeGeometrySimulationOutput *data = MEM_cnew<NodeGeometrySimulationOutput>(__func__);
|
||||
|
||||
data->next_identifier = 0;
|
||||
|
||||
data->items = MEM_cnew_array<NodeSimulationItem>(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;
|
||||
}
|
||||
|
||||
|
@ -300,8 +280,11 @@ static void node_copy_storage(bNodeTree * /*dst_tree*/, bNode *dst_node, const b
|
|||
|
||||
dst_storage->items = MEM_cnew_array<NodeSimulationItem>(src_storage.items_num, __func__);
|
||||
dst_storage->items_num = src_storage.items_num;
|
||||
dst_storage->active_index = src_storage.active_index;
|
||||
dst_storage->next_identifier = src_storage.next_identifier;
|
||||
for (const int i : IndexRange(src_storage.items_num)) {
|
||||
if (char *name = src_storage.items[i].name) {
|
||||
dst_storage->items[i].identifier = src_storage.items[i].identifier;
|
||||
dst_storage->items[i].name = BLI_strdup(name);
|
||||
dst_storage->items[i].socket_type = src_storage.items[i].socket_type;
|
||||
}
|
||||
|
@ -315,8 +298,8 @@ static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
|
|||
NodeGeometrySimulationOutput &storage = node_storage(*node);
|
||||
if (link->tonode == node) {
|
||||
if (link->tosock->identifier == StringRef("__extend__")) {
|
||||
if (const NodeSimulationItem *item = simulation_item_add_from_socket(storage,
|
||||
*link->fromsock)) {
|
||||
if (const NodeSimulationItem *item = NOD_geometry_simulation_output_add_item_from_socket(
|
||||
&storage, link->fromnode, link->fromsock)) {
|
||||
update_node_declaration_and_sockets(*ntree, *node);
|
||||
link->tosock = nodeFindSocket(node, SOCK_IN, item->name);
|
||||
}
|
||||
|
@ -328,8 +311,8 @@ static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
|
|||
else {
|
||||
BLI_assert(link->fromnode == node);
|
||||
if (link->fromsock->identifier == StringRef("__extend__")) {
|
||||
if (const NodeSimulationItem *item = simulation_item_add_from_socket(storage,
|
||||
*link->tosock)) {
|
||||
if (const NodeSimulationItem *item = NOD_geometry_simulation_output_add_item_from_socket(
|
||||
&storage, link->fromnode, link->tosock)) {
|
||||
update_node_declaration_and_sockets(*ntree, *node);
|
||||
link->fromsock = nodeFindSocket(node, SOCK_OUT, item->name);
|
||||
}
|
||||
|
@ -360,3 +343,202 @@ void register_node_type_geo_simulation_output()
|
|||
file_ns::node_copy_storage);
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
||||
blender::Span<NodeSimulationItem> NodeGeometrySimulationOutput::items_span() const
|
||||
{
|
||||
return blender::Span<NodeSimulationItem>(items, items_num);
|
||||
}
|
||||
|
||||
blender::MutableSpan<NodeSimulationItem> NodeGeometrySimulationOutput::items_span_for_write()
|
||||
{
|
||||
return blender::MutableSpan<NodeSimulationItem>(items, items_num);
|
||||
}
|
||||
|
||||
blender::IndexRange NodeGeometrySimulationOutput::items_range() const
|
||||
{
|
||||
return blender::IndexRange(items_num);
|
||||
}
|
||||
|
||||
bool NOD_geometry_simulation_output_item_socket_type_supported(
|
||||
const eNodeSocketDatatype socket_type)
|
||||
{
|
||||
return ELEM(socket_type, SOCK_GEOMETRY);
|
||||
}
|
||||
|
||||
bNode *NOD_geometry_simulation_output_find_node_by_item(bNodeTree *ntree,
|
||||
const NodeSimulationItem *item)
|
||||
{
|
||||
ntree->ensure_topology_cache();
|
||||
for (bNode *node : ntree->nodes_by_type("GeometryNodeSimulationOutput")) {
|
||||
NodeGeometrySimulationOutput *sim = static_cast<NodeGeometrySimulationOutput *>(node->storage);
|
||||
if (sim->items_span().contains_ptr(item)) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool NOD_geometry_simulation_output_item_set_unique_name(NodeGeometrySimulationOutput *sim,
|
||||
NodeSimulationItem *item,
|
||||
const char *name,
|
||||
const char *defname)
|
||||
{
|
||||
char unique_name[MAX_NAME + 4];
|
||||
BLI_strncpy(unique_name, name, sizeof(unique_name));
|
||||
|
||||
blender::nodes::SimulationItemsUniqueNameArgs args{sim, item};
|
||||
const bool name_changed = BLI_uniquename_cb(blender::nodes::simulation_items_unique_name_check,
|
||||
&args,
|
||||
defname,
|
||||
'.',
|
||||
unique_name,
|
||||
ARRAY_SIZE(unique_name));
|
||||
item->name = BLI_strdup(unique_name);
|
||||
return name_changed;
|
||||
}
|
||||
|
||||
bool NOD_geometry_simulation_output_contains_item(NodeGeometrySimulationOutput *sim,
|
||||
const NodeSimulationItem *item)
|
||||
{
|
||||
return sim->items_span().contains_ptr(item);
|
||||
}
|
||||
|
||||
NodeSimulationItem *NOD_geometry_simulation_output_get_active_item(
|
||||
NodeGeometrySimulationOutput *sim)
|
||||
{
|
||||
if (!sim->items_range().contains(sim->active_index)) {
|
||||
return nullptr;
|
||||
}
|
||||
return &sim->items[sim->active_index];
|
||||
}
|
||||
|
||||
void NOD_geometry_simulation_output_set_active_item(NodeGeometrySimulationOutput *sim,
|
||||
NodeSimulationItem *item)
|
||||
{
|
||||
if (sim->items_span().contains_ptr(item)) {
|
||||
sim->active_index = item - sim->items;
|
||||
}
|
||||
}
|
||||
|
||||
NodeSimulationItem *NOD_geometry_simulation_output_find_item(NodeGeometrySimulationOutput *sim,
|
||||
const char *name)
|
||||
{
|
||||
for (NodeSimulationItem &item : sim->items_span_for_write()) {
|
||||
if (STREQ(item.name, name)) {
|
||||
return &item;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NodeSimulationItem *NOD_geometry_simulation_output_add_item(NodeGeometrySimulationOutput *sim,
|
||||
const short socket_type,
|
||||
const char *name)
|
||||
{
|
||||
return NOD_geometry_simulation_output_insert_item(sim, socket_type, name, sim->items_num);
|
||||
}
|
||||
|
||||
NodeSimulationItem *NOD_geometry_simulation_output_insert_item(NodeGeometrySimulationOutput *sim,
|
||||
const short socket_type,
|
||||
const char *name,
|
||||
int index)
|
||||
{
|
||||
NodeSimulationItem *old_items = sim->items;
|
||||
sim->items = MEM_cnew_array<NodeSimulationItem>(sim->items_num + 1, __func__);
|
||||
for (const int i : blender::IndexRange(index)) {
|
||||
sim->items[i] = old_items[i];
|
||||
}
|
||||
for (const int i : blender::IndexRange(index, sim->items_num - index)) {
|
||||
sim->items[i + 1] = old_items[i];
|
||||
}
|
||||
|
||||
const char *defname = nodeStaticSocketLabel(socket_type, 0);
|
||||
NodeSimulationItem &added_item = sim->items[index];
|
||||
added_item.identifier = sim->next_identifier++;
|
||||
NOD_geometry_simulation_output_item_set_unique_name(sim, &added_item, name, defname);
|
||||
added_item.socket_type = socket_type;
|
||||
|
||||
sim->items_num++;
|
||||
MEM_SAFE_FREE(old_items);
|
||||
|
||||
return &added_item;
|
||||
}
|
||||
|
||||
NodeSimulationItem *NOD_geometry_simulation_output_add_item_from_socket(
|
||||
NodeGeometrySimulationOutput *sim, const bNode * /*from_node*/, const bNodeSocket *from_sock)
|
||||
{
|
||||
if (from_sock->type != SOCK_GEOMETRY) {
|
||||
return nullptr;
|
||||
}
|
||||
return NOD_geometry_simulation_output_insert_item(
|
||||
sim, from_sock->type, from_sock->name, sim->items_num);
|
||||
}
|
||||
|
||||
NodeSimulationItem *NOD_geometry_simulation_output_insert_item_from_socket(
|
||||
NodeGeometrySimulationOutput *sim,
|
||||
const bNode * /*from_node*/,
|
||||
const bNodeSocket *from_sock,
|
||||
int index)
|
||||
{
|
||||
return NOD_geometry_simulation_output_insert_item(sim, from_sock->type, from_sock->name, index);
|
||||
}
|
||||
|
||||
void NOD_geometry_simulation_output_remove_item(NodeGeometrySimulationOutput *sim,
|
||||
NodeSimulationItem *item)
|
||||
{
|
||||
const int index = item - sim->items;
|
||||
if (index < 0 || index >= sim->items_num) {
|
||||
return;
|
||||
}
|
||||
|
||||
NodeSimulationItem *old_items = sim->items;
|
||||
sim->items = MEM_cnew_array<NodeSimulationItem>(sim->items_num - 1, __func__);
|
||||
for (const int i : blender::IndexRange(index)) {
|
||||
sim->items[i] = old_items[i];
|
||||
}
|
||||
for (const int i : blender::IndexRange(index, sim->items_num - index).drop_front(1)) {
|
||||
sim->items[i - 1] = old_items[i];
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(old_items[index].name);
|
||||
|
||||
sim->items_num--;
|
||||
MEM_SAFE_FREE(old_items);
|
||||
}
|
||||
|
||||
void NOD_geometry_simulation_output_clear_items(struct NodeGeometrySimulationOutput *sim)
|
||||
{
|
||||
for (NodeSimulationItem &item : sim->items_span_for_write()) {
|
||||
MEM_SAFE_FREE(item.name);
|
||||
}
|
||||
MEM_SAFE_FREE(sim->items);
|
||||
sim->items = nullptr;
|
||||
sim->items_num = 0;
|
||||
}
|
||||
|
||||
void NOD_geometry_simulation_output_move_item(NodeGeometrySimulationOutput *sim,
|
||||
int from_index,
|
||||
int to_index)
|
||||
{
|
||||
BLI_assert(from_index >= 0 && from_index < sim->items_num);
|
||||
BLI_assert(to_index >= 0 && to_index < sim->items_num);
|
||||
|
||||
if (from_index == to_index) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (from_index < to_index) {
|
||||
const NodeSimulationItem tmp = sim->items[from_index];
|
||||
for (int i = from_index; i < to_index; ++i) {
|
||||
sim->items[i] = sim->items[i + 1];
|
||||
}
|
||||
sim->items[to_index] = tmp;
|
||||
}
|
||||
else /* from_index > to_index */ {
|
||||
const NodeSimulationItem tmp = sim->items[from_index];
|
||||
for (int i = from_index; i > to_index; --i) {
|
||||
sim->items[i] = sim->items[i - 1];
|
||||
}
|
||||
sim->items[to_index] = tmp;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,13 @@ using namespace blender;
|
|||
using blender::fn::ValueOrField;
|
||||
using blender::nodes::SocketDeclarationPtr;
|
||||
|
||||
extern "C" void ED_node_type_draw_color(const char *idname, float *r_color);
|
||||
|
||||
void node_type_draw_color(const char *idname, float *r_color)
|
||||
{
|
||||
ED_node_type_draw_color(idname, r_color);
|
||||
}
|
||||
|
||||
struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree,
|
||||
struct bNode *node,
|
||||
struct bNodeSocketTemplate *stemp,
|
||||
|
|
Loading…
Reference in New Issue