Geometry Nodes: new String to Value node
An existing node converts a value (float) to string. This node is intended as a conversion in the other direction. If parsing is unsuccessful, floating point 0 is output. This node also outputs the length of the parsed string (i.e. the index of the first character where the number stopped). Pull Request: https://projects.blender.org/blender/blender/pulls/112174
This commit is contained in:
committed by
Jacques Lucke
parent
b8051d12ac
commit
ad83a1017f
@@ -624,6 +624,7 @@ class NODE_MT_category_GEO_TEXT(Menu):
|
||||
node_add_menu.add_node_type(layout, "FunctionNodeFindInString")
|
||||
node_add_menu.add_node_type(layout, "FunctionNodeStringLength")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeStringToCurves")
|
||||
node_add_menu.add_node_type(layout, "FunctionNodeStringToValue")
|
||||
node_add_menu.add_node_type(layout, "FunctionNodeValueToString")
|
||||
layout.separator()
|
||||
node_add_menu.add_node_type(layout, "FunctionNodeInputSpecialCharacters")
|
||||
|
||||
@@ -10088,6 +10088,7 @@ static void rna_def_nodes(BlenderRNA *brna)
|
||||
define("FunctionNode", "FunctionNodeSeparateTransform");
|
||||
define("FunctionNode", "FunctionNodeSliceString");
|
||||
define("FunctionNode", "FunctionNodeStringLength");
|
||||
define("FunctionNode", "FunctionNodeStringToValue");
|
||||
define("FunctionNode", "FunctionNodeTransformDirection");
|
||||
define("FunctionNode", "FunctionNodeTransformPoint");
|
||||
define("FunctionNode", "FunctionNodeTransposeMatrix");
|
||||
|
||||
@@ -14,6 +14,7 @@ set(INC
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
../../../../extern/fast_float
|
||||
)
|
||||
|
||||
set(SRC
|
||||
@@ -60,6 +61,7 @@ set(SRC
|
||||
nodes/node_fn_separate_transform.cc
|
||||
nodes/node_fn_slice_string.cc
|
||||
nodes/node_fn_string_length.cc
|
||||
nodes/node_fn_string_to_value.cc
|
||||
nodes/node_fn_transform_direction.cc
|
||||
nodes/node_fn_transform_point.cc
|
||||
nodes/node_fn_transpose_matrix.cc
|
||||
|
||||
145
source/blender/nodes/function/nodes/node_fn_string_to_value.cc
Normal file
145
source/blender/nodes/function/nodes/node_fn_string_to_value.cc
Normal file
@@ -0,0 +1,145 @@
|
||||
/* SPDX-FileCopyrightText: 2025 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BLI_string_utf8.h"
|
||||
|
||||
#include "fast_float.h"
|
||||
|
||||
#include "node_function_util.hh"
|
||||
|
||||
#include "NOD_rna_define.hh"
|
||||
#include "NOD_socket_search_link.hh"
|
||||
|
||||
#include "UI_interface_layout.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
#include <charconv>
|
||||
|
||||
namespace blender::nodes::node_fn_string_to_value_cc {
|
||||
|
||||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::String>("String").hide_label();
|
||||
|
||||
const bNode *node = b.node_or_null();
|
||||
if (node != nullptr) {
|
||||
const eNodeSocketDatatype data_type = eNodeSocketDatatype(node->custom1);
|
||||
b.add_output(data_type, "Value");
|
||||
}
|
||||
|
||||
b.add_output<decl::Int>("Length");
|
||||
}
|
||||
|
||||
static const mf::MultiFunction *get_multi_function(const bNode &bnode)
|
||||
{
|
||||
static auto str_to_float_fn = mf::build::SI1_SO2<std::string, float, int>(
|
||||
"String to Value", [](const std::string &s, float &value, int &length) -> void {
|
||||
const auto result = fast_float::from_chars(s.data(), s.data() + s.size(), value);
|
||||
length = BLI_strnlen_utf8(s.data(), result.ptr - s.data());
|
||||
});
|
||||
|
||||
static auto str_to_int_fn = mf::build::SI1_SO2<std::string, int, int>(
|
||||
"String to Value", [](const std::string &s, int &value, int &length) -> void {
|
||||
const auto result = std::from_chars(s.data(), s.data() + s.size(), value);
|
||||
length = BLI_strnlen_utf8(s.data(), result.ptr - s.data());
|
||||
});
|
||||
|
||||
switch (eNodeSocketDatatype(bnode.custom1)) {
|
||||
case SOCK_FLOAT:
|
||||
return &str_to_float_fn;
|
||||
case SOCK_INT:
|
||||
return &str_to_int_fn;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
|
||||
{
|
||||
const mf::MultiFunction *fn = get_multi_function(builder.node());
|
||||
builder.set_matching_fn(fn);
|
||||
}
|
||||
|
||||
static void node_init(bNodeTree *, bNode *node)
|
||||
{
|
||||
node->custom1 = SOCK_FLOAT;
|
||||
}
|
||||
|
||||
static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms)
|
||||
{
|
||||
const eNodeSocketDatatype socket_type = eNodeSocketDatatype(params.other_socket().type);
|
||||
if (params.in_out() == SOCK_IN) {
|
||||
if (socket_type == SOCK_STRING) {
|
||||
params.add_item(IFACE_("String"), [](LinkSearchOpParams ¶ms) {
|
||||
bNode &node = params.add_node("FunctionNodeStringToValue");
|
||||
params.update_and_connect_available_socket(node, "String");
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (params.in_out() == SOCK_OUT) {
|
||||
if (socket_type == SOCK_INT || socket_type == SOCK_BOOLEAN) {
|
||||
params.add_item(IFACE_("Value"), [](LinkSearchOpParams ¶ms) {
|
||||
bNode &node = params.add_node("FunctionNodeStringToValue");
|
||||
node.custom1 = SOCK_INT;
|
||||
params.update_and_connect_available_socket(node, "Value");
|
||||
});
|
||||
}
|
||||
else if (params.node_tree().typeinfo->validate_link(SOCK_FLOAT, socket_type)) {
|
||||
params.add_item(IFACE_("Value"), [](LinkSearchOpParams ¶ms) {
|
||||
bNode &node = params.add_node("FunctionNodeStringToValue");
|
||||
node.custom1 = SOCK_FLOAT;
|
||||
params.update_and_connect_available_socket(node, "Value");
|
||||
});
|
||||
}
|
||||
|
||||
if (socket_type == SOCK_INT) {
|
||||
params.add_item(IFACE_("Length"), [](LinkSearchOpParams ¶ms) {
|
||||
bNode &node = params.add_node("FunctionNodeStringToValue");
|
||||
params.update_and_connect_available_socket(node, "Length");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
|
||||
{
|
||||
layout->prop(ptr, "data_type", UI_ITEM_NONE, "", ICON_NONE);
|
||||
}
|
||||
|
||||
static void node_rna(StructRNA *srna)
|
||||
{
|
||||
static const EnumPropertyItem data_types[] = {
|
||||
{SOCK_FLOAT, "FLOAT", ICON_NODE_SOCKET_FLOAT, "Float", "Floating-point value"},
|
||||
{SOCK_INT, "INT", ICON_NODE_SOCKET_INT, "Integer", "32-bit integer"},
|
||||
{0, nullptr, 0, nullptr, nullptr}};
|
||||
|
||||
RNA_def_node_enum(srna,
|
||||
"data_type",
|
||||
"Data Type",
|
||||
"",
|
||||
data_types,
|
||||
NOD_inline_enum_accessors(custom1),
|
||||
SOCK_FLOAT);
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
{
|
||||
static blender::bke::bNodeType ntype;
|
||||
|
||||
fn_node_type_base(&ntype, "FunctionNodeStringToValue");
|
||||
ntype.ui_name = "String to Value";
|
||||
ntype.nclass = NODE_CLASS_CONVERTER;
|
||||
ntype.declare = node_declare;
|
||||
ntype.initfunc = node_init;
|
||||
ntype.draw_buttons = node_layout;
|
||||
ntype.build_multi_function = node_build_multi_function;
|
||||
ntype.gather_link_search_ops = node_gather_link_searches;
|
||||
blender::bke::node_register_type(ntype);
|
||||
|
||||
node_rna(ntype.rna_ext.srna);
|
||||
}
|
||||
NOD_REGISTER_NODE(node_register)
|
||||
|
||||
} // namespace blender::nodes::node_fn_string_to_value_cc
|
||||
Reference in New Issue
Block a user