Geometry Nodes: simplify supporting different input socket types for attributes

This is a non-functional change. The functionality introduced in this commit
is not used in master yet. It is used by nodes that are being developed in
other branches though.
This commit is contained in:
Jacques Lucke 2020-12-09 16:20:48 +01:00
parent 25e151cc34
commit 4a5f36638b
7 changed files with 136 additions and 0 deletions

View File

@ -157,6 +157,14 @@ class GeometryComponent {
const CustomDataType data_type,
const void *value) const;
/* Create a read-only dummy attribute that always returns the same value.
* The given value is converted to the correct type if necessary. */
blender::bke::ReadAttributePtr attribute_get_constant_for_read_converted(
const AttributeDomain domain,
const CustomDataType in_data_type,
const CustomDataType out_data_type,
const void *value) const;
/* Get a read-only dummy attribute that always returns the same value. */
template<typename T>
blender::bke::TypedReadAttribute<T> attribute_get_constant_for_read(const AttributeDomain domain,

View File

@ -668,6 +668,39 @@ blender::bke::ReadAttributePtr GeometryComponent::attribute_get_constant_for_rea
domain, domain_size, *cpp_type, value);
}
blender::bke::ReadAttributePtr GeometryComponent::attribute_get_constant_for_read_converted(
const AttributeDomain domain,
const CustomDataType in_data_type,
const CustomDataType out_data_type,
const void *value) const
{
BLI_assert(this->attribute_domain_supported(domain));
if (value == nullptr || in_data_type == out_data_type) {
return this->attribute_get_constant_for_read(domain, out_data_type, value);
}
const blender::fn::CPPType *in_cpp_type = blender::bke::custom_data_type_to_cpp_type(
in_data_type);
const blender::fn::CPPType *out_cpp_type = blender::bke::custom_data_type_to_cpp_type(
out_data_type);
BLI_assert(in_cpp_type != nullptr);
BLI_assert(out_cpp_type != nullptr);
const blender::nodes::DataTypeConversions &conversions =
blender::nodes::get_implicit_type_conversions();
BLI_assert(conversions.is_convertible(*in_cpp_type, *out_cpp_type));
void *out_value = alloca(out_cpp_type->size());
conversions.convert(*in_cpp_type, *out_cpp_type, value, out_value);
const int domain_size = this->attribute_domain_size(domain);
blender::bke::ReadAttributePtr attribute = std::make_unique<blender::bke::ConstantReadAttribute>(
domain, domain_size, *out_cpp_type, out_value);
out_cpp_type->destruct(out_value);
return attribute;
}
WriteAttributePtr GeometryComponent::attribute_try_ensure_for_write(const StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type)

View File

@ -1464,6 +1464,13 @@ typedef enum GeometryNodeUseAttributeFlag {
GEO_NODE_USE_ATTRIBUTE_B = (1 << 1),
} GeometryNodeUseAttributeFlag;
typedef enum GeometryNodeAttributeInputMode {
GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE = 0,
GEO_NODE_ATTRIBUTE_INPUT_FLOAT = 1,
GEO_NODE_ATTRIBUTE_INPUT_VECTOR = 2,
GEO_NODE_ATTRIBUTE_INPUT_COLOR = 3,
} GeometryNodeAttributeInputMode;
#ifdef __cplusplus
}
#endif

View File

@ -148,6 +148,26 @@ class GeoNodeExecParams {
return self_object_;
}
/**
* Creates a read-only attribute based on node inputs. The method automatically detects which
* input with the given name is available.
*/
ReadAttributePtr get_input_attribute(const StringRef name,
const GeometryComponent &component,
const AttributeDomain domain,
const CustomDataType type,
const void *default_value) const;
template<typename T>
bke::TypedReadAttribute<T> get_input_attribute(const StringRef name,
const GeometryComponent &component,
const AttributeDomain domain,
const T &default_value) const
{
const CustomDataType type = bke::cpp_type_to_custom_data_type(CPPType::get<T>());
return this->get_input_attribute(name, component, domain, type, &default_value);
}
private:
/* Utilities for detecting common errors at when using this class. */
void check_extract_input(StringRef identifier, const CPPType *requested_type = nullptr) const;

View File

@ -17,6 +17,27 @@
#include "node_geometry_util.hh"
#include "node_util.h"
namespace blender::nodes {
void update_attribute_input_socket_availabilities(bNode &node,
const StringRef name,
const GeometryNodeAttributeInputMode mode)
{
const GeometryNodeAttributeInputMode mode_ = (GeometryNodeAttributeInputMode)mode;
LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
if (name == socket->name) {
const bool is_available =
((socket->type == SOCK_STRING && mode_ == GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE) ||
(socket->type == SOCK_FLOAT && mode_ == GEO_NODE_ATTRIBUTE_INPUT_FLOAT) ||
(socket->type == SOCK_VECTOR && mode_ == GEO_NODE_ATTRIBUTE_INPUT_VECTOR) ||
(socket->type == SOCK_RGBA && mode_ == GEO_NODE_ATTRIBUTE_INPUT_COLOR));
nodeSetSocketAvailability(socket, is_available);
}
}
}
} // namespace blender::nodes
bool geo_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
{
return STREQ(ntree->idname, "GeometryNodeTree");

View File

@ -37,3 +37,9 @@
void geo_node_type_base(
struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
bool geo_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree);
namespace blender::nodes {
void update_attribute_input_socket_availabilities(bNode &node,
const StringRef name,
const GeometryNodeAttributeInputMode mode);
}

View File

@ -19,6 +19,47 @@
namespace blender::nodes {
ReadAttributePtr GeoNodeExecParams::get_input_attribute(const StringRef name,
const GeometryComponent &component,
const AttributeDomain domain,
const CustomDataType type,
const void *default_value) const
{
const bNodeSocket *found_socket = nullptr;
LISTBASE_FOREACH (const bNodeSocket *, socket, &node_.inputs) {
if ((socket->flag & SOCK_UNAVAIL) != 0) {
continue;
}
if (name == socket->name) {
found_socket = socket;
break;
}
}
BLI_assert(found_socket != nullptr);
if (found_socket->type == SOCK_STRING) {
const std::string name = this->get_input<std::string>(found_socket->identifier);
return component.attribute_get_for_read(name, domain, type, default_value);
}
if (found_socket->type == SOCK_FLOAT) {
const float value = this->get_input<float>(found_socket->identifier);
return component.attribute_get_constant_for_read_converted(
domain, CD_PROP_FLOAT, type, &value);
}
if (found_socket->type == SOCK_VECTOR) {
const float3 value = this->get_input<float3>(found_socket->identifier);
return component.attribute_get_constant_for_read_converted(
domain, CD_PROP_FLOAT3, type, &value);
}
if (found_socket->type == SOCK_RGBA) {
const Color4f value = this->get_input<Color4f>(found_socket->identifier);
return component.attribute_get_constant_for_read_converted(
domain, CD_PROP_COLOR, type, &value);
}
BLI_assert(false);
return component.attribute_get_constant_for_read(domain, type, default_value);
}
void GeoNodeExecParams::check_extract_input(StringRef identifier,
const CPPType *requested_type) const
{