WIP: Nodes: improve data type display for sockets #124300

Draft
Jacques Lucke wants to merge 6 commits from JacquesLucke/blender:data-type-tooltip into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
12 changed files with 99 additions and 71 deletions

View File

@ -1309,6 +1309,18 @@ void node_socket_color_get(const bContext &C,
sock.typeinfo->draw_color((bContext *)&C, &ptr, &node_ptr, r_color);
}
static geo_log::GeoTreeLog *geo_tree_log_for_socket(const bNodeTree &ntree,
const bNodeSocket &socket,
TreeDrawContext &tree_draw_ctx)
{
const bNodeTreeZones *zones = ntree.zones();
if (!zones) {
return nullptr;
}
const bNodeTreeZone *zone = zones->get_zone_by_socket(socket);
return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr);
}
static void create_inspection_string_for_generic_value(const bNodeSocket &socket,
const GPointer value,
fmt::memory_buffer &buf)
@ -1500,13 +1512,12 @@ static void create_inspection_string_for_geometry_info(const geo_log::GeometryIn
Span<bke::GeometryComponent::Type> component_types = value_log.component_types;
if (component_types.is_empty()) {
fmt::format_to(fmt::appender(buf), TIP_("Empty Geometry"));
fmt::format_to(fmt::appender(buf), TIP_("Empty"));
return;
}
fmt::format_to(fmt::appender(buf), TIP_("Geometry:"));
if (!value_log.name.empty()) {
fmt::format_to(fmt::appender(buf), " \"{}\"", value_log.name);
fmt::format_to(fmt::appender(buf), "\"{}\"", value_log.name);
}
fmt::format_to(fmt::appender(buf), "\n");
for (bke::GeometryComponent::Type type : component_types) {
@ -1673,11 +1684,14 @@ static std::optional<std::string> create_description_inspection_string(const bNo
return TIP_(description.c_str());
}
static std::optional<std::string> create_log_inspection_string(geo_log::GeoTreeLog *geo_tree_log,
const bNodeSocket &socket)
static std::optional<std::string> create_log_inspection_string(const bNodeTree &ntree,
const bNodeSocket &socket,
TreeDrawContext &tree_draw_ctx)
{
using namespace blender::nodes::geo_eval_log;
geo_log::GeoTreeLog *geo_tree_log = geo_tree_log_for_socket(ntree, socket, tree_draw_ctx);
if (geo_tree_log == nullptr) {
return std::nullopt;
}
@ -1711,7 +1725,8 @@ static std::optional<std::string> create_log_inspection_string(geo_log::GeoTreeL
return str;
}
static std::optional<std::string> create_declaration_inspection_string(const bNodeSocket &socket)
static std::optional<std::string> create_supported_types_inspection_string(
const bNodeSocket &socket)
{
fmt::memory_buffer buf;
if (const nodes::decl::Geometry *socket_decl = dynamic_cast<const nodes::decl::Geometry *>(
@ -1727,18 +1742,6 @@ static std::optional<std::string> create_declaration_inspection_string(const bNo
return str;
}
static geo_log::GeoTreeLog *geo_tree_log_for_socket(const bNodeTree &ntree,
const bNodeSocket &socket,
TreeDrawContext &tree_draw_ctx)
{
const bNodeTreeZones *zones = ntree.zones();
if (!zones) {
return nullptr;
}
const bNodeTreeZone *zone = zones->get_zone_by_socket(socket);
return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr);
}
static Vector<std::string> lines_of_text(std::string text)
{
Vector<std::string> result;
@ -1772,10 +1775,8 @@ static std::optional<std::string> create_multi_input_log_inspection_string(
continue;
}
const bNodeSocket &connected_socket = *link->fromsock;
geo_log::GeoTreeLog *geo_tree_log = geo_tree_log_for_socket(
const std::optional<std::string> input_log = create_log_inspection_string(
ntree, connected_socket, tree_draw_ctx);
const std::optional<std::string> input_log = create_log_inspection_string(geo_tree_log,
connected_socket);
if (!input_log.has_value()) {
continue;
}
@ -1820,6 +1821,27 @@ static std::optional<std::string> create_default_value_inspection_string(const b
return str;
}
static std::optional<std::string> create_last_value_inspection_string(
const bNodeTree &ntree, const bNodeSocket &socket, TreeDrawContext &tree_draw_ctx)
{
if (std::optional<std::string> info = create_log_inspection_string(ntree, socket, tree_draw_ctx))
{
return info;
}
if (std::optional<std::string> info = create_default_value_inspection_string(socket)) {
return info;
}
if (std::optional<std::string> info = create_multi_input_log_inspection_string(
ntree, socket, tree_draw_ctx))
{
return info;
}
if (ntree.type == NTREE_GEOMETRY) {
return TIP_("Unknown");
}
return std::nullopt;
}
static const bNodeSocket *target_for_reroute(const bNodeSocket &reroute_output)
{
const bNodeSocket *output = &reroute_output;
@ -1883,6 +1905,8 @@ static std::string node_socket_get_tooltip(const SpaceNode *snode,
const bNodeTree &ntree,
const bNodeSocket &socket)
{
const bNode &node = socket.owner_node();
TreeDrawContext tree_draw_ctx;
if (snode != nullptr) {
if (ntree.type == NTREE_GEOMETRY) {
@ -1891,30 +1915,48 @@ static std::string node_socket_get_tooltip(const SpaceNode *snode,
}
}
geo_log::GeoTreeLog *geo_tree_log = geo_tree_log_for_socket(ntree, socket, tree_draw_ctx);
/* Handle reroute nodes as a special case. */
if (node.is_reroute()) {
if (const std::optional<std::string> info = create_dangling_reroute_inspection_string(ntree,
socket))
{
return *info;
}
if (std::optional<std::string> info = create_log_inspection_string(
ntree, socket, tree_draw_ctx))
{
return *info;
}
char reroute_name[MAX_NAME];
bke::nodeLabel(&ntree, &node, reroute_name, sizeof(reroute_name));
return reroute_name;
}
/* Handle extend sockets as a special case. */
const bool is_extend_socket = StringRef(socket.idname) == "NodeSocketVirtual";
if (is_extend_socket) {
return TIP_("Connect a link to create a new socket");
}
Vector<std::string> inspection_strings;
/* Description. */
if (std::optional<std::string> info = create_description_inspection_string(socket)) {
inspection_strings.append(std::move(*info));
}
if (std::optional<std::string> info = create_log_inspection_string(geo_tree_log, socket)) {
inspection_strings.append(std::move(*info));
}
else if (std::optional<std::string> info = create_dangling_reroute_inspection_string(ntree,
socket))
/* Last value. */
if (std::optional<std::string> info = create_last_value_inspection_string(
ntree, socket, tree_draw_ctx))
{
inspection_strings.append(std::move(*info));
inspection_strings.append(fmt::format("Last value: {}", *info));
}
else if (std::optional<std::string> info = create_default_value_inspection_string(socket)) {
inspection_strings.append(std::move(*info));
}
else if (std::optional<std::string> info = create_multi_input_log_inspection_string(
ntree, socket, tree_draw_ctx))
{
inspection_strings.append(std::move(*info));
}
if (std::optional<std::string> info = create_declaration_inspection_string(socket)) {
/* Socket type. */
inspection_strings.append(fmt::format(TIP_("Socket type: {}"), TIP_(socket.typeinfo->label)));
/* Supported types. */
if (std::optional<std::string> info = create_supported_types_inspection_string(socket)) {
inspection_strings.append(std::move(*info));
}
@ -1926,29 +1968,6 @@ static std::string node_socket_get_tooltip(const SpaceNode *snode,
}
}
if (inspection_strings.is_empty()) {
const bool is_extend = StringRef(socket.idname) == "NodeSocketVirtual";
const bNode &node = socket.owner_node();
if (node.is_reroute()) {
char reroute_name[MAX_NAME];
bke::nodeLabel(&ntree, &node, reroute_name, sizeof(reroute_name));
output << reroute_name;
}
else if (is_extend) {
output << TIP_("Connect a link to create a new socket");
}
else {
output << bke::nodeSocketLabel(&socket);
}
if (ntree.type == NTREE_GEOMETRY && !is_extend) {
output << ".\n\n";
output << TIP_(
"Unknown socket value. Either the socket was not used or its value was not logged "
"during the last evaluation");
}
}
return output.str();
}

View File

@ -189,6 +189,7 @@ class SocketDeclaration : public ItemDeclaration {
bool is_default_link_socket = false;
/** Puts this socket on the same line as the previous one in the UI. */
bool align_with_previous_socket = false;
bool is_volume_grid = false;
InputSocketFieldType input_field_type = InputSocketFieldType::None;
OutputFieldDependency output_field_dependency;
@ -384,6 +385,8 @@ class BaseSocketDeclarationBuilder {
const void *data,
StringRef property_name);
BaseSocketDeclarationBuilder &is_volume_grid(bool value = true);
/** Index in the list of inputs or outputs. */
int index() const;

View File

@ -33,7 +33,7 @@ static void node_declare(NodeDeclarationBuilder &b)
return;
}
b.add_output(eNodeSocketDatatype(node->custom1), "Grid");
b.add_output(eNodeSocketDatatype(node->custom1), "Grid").is_volume_grid();
}
static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)

View File

@ -15,7 +15,7 @@ namespace blender::nodes::node_geo_grid_to_mesh_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Float>("Grid").hide_value();
b.add_input<decl::Float>("Grid").hide_value().is_volume_grid();
b.add_input<decl::Float>("Threshold")
.default_value(0.1f)
.description("Values larger than the threshold are inside the generated mesh");

View File

@ -28,7 +28,7 @@ static void node_declare(NodeDeclarationBuilder &b)
.max(FLT_MAX)
.subtype(PROP_DISTANCE)
.description("Width of the gradient inside of the mesh");
b.add_output<decl::Float>("Density Grid");
b.add_output<decl::Float>("Density Grid").is_volume_grid();
}
static void node_geo_exec(GeoNodeExecParams params)

View File

@ -24,7 +24,7 @@ static void node_declare(NodeDeclarationBuilder &b)
.min(1)
.max(100)
.description("Width of the active voxel surface, in voxels");
b.add_output<decl::Float>("SDF Grid");
b.add_output<decl::Float>("SDF Grid").is_volume_grid();
}
static void node_geo_exec(GeoNodeExecParams params)

View File

@ -20,7 +20,7 @@ static void node_declare(NodeDeclarationBuilder &b)
.subtype(PROP_DISTANCE)
.field_on_all();
b.add_input<decl::Float>("Voxel Size").default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE);
b.add_output<decl::Float>("SDF Grid");
b.add_output<decl::Float>("SDF Grid").is_volume_grid();
}
#ifdef WITH_OPENVDB

View File

@ -36,7 +36,7 @@ static void node_declare(NodeDeclarationBuilder &b)
}
const eNodeSocketDatatype data_type = eNodeSocketDatatype(node->custom1);
b.add_input(data_type, "Grid").hide_value();
b.add_input(data_type, "Grid").hide_value().is_volume_grid();
b.add_input<decl::Vector>("Position").implicit_field(implicit_field_inputs::position);
b.add_output(data_type, "Value").dependent_field({1});

View File

@ -26,7 +26,7 @@ static void node_declare(NodeDeclarationBuilder &b)
}
const eNodeSocketDatatype data_type = eNodeSocketDatatype(node->custom1);
b.add_input(data_type, "Grid").hide_value();
b.add_input(data_type, "Grid").hide_value().is_volume_grid();
b.add_input<decl::Int>("X").supports_field();
b.add_input<decl::Int>("Y").supports_field();
b.add_input<decl::Int>("Z").supports_field();

View File

@ -28,10 +28,10 @@ enum class Operation {
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Float>("Grid 1").hide_value();
b.add_input<decl::Float>("Grid 2").hide_value().multi_input().make_available(
b.add_input<decl::Float>("Grid 1").hide_value().is_volume_grid();
b.add_input<decl::Float>("Grid 2").hide_value().multi_input().is_volume_grid().make_available(
[](bNode &node) { node.custom1 = int16_t(Operation::Difference); });
b.add_output<decl::Float>("Grid").hide_value();
b.add_output<decl::Float>("Grid").hide_value().is_volume_grid();
}
static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)

View File

@ -29,7 +29,7 @@ static void node_declare(NodeDeclarationBuilder &b)
return;
}
b.add_input(eCustomDataType(node->custom1), "Grid").hide_value();
b.add_input(eCustomDataType(node->custom1), "Grid").hide_value().is_volume_grid();
}
static void search_link_ops(GatherLinkSearchOpParams &params)

View File

@ -756,6 +756,12 @@ BaseSocketDeclarationBuilder &BaseSocketDeclarationBuilder::socket_name_ptr(
property_name);
}
BaseSocketDeclarationBuilder &BaseSocketDeclarationBuilder::is_volume_grid(const bool value)
{
decl_base_->is_volume_grid = value;
return *this;
}
OutputFieldDependency OutputFieldDependency::ForFieldSource()
{
OutputFieldDependency field_dependency;