Blender  V2.93
node_geo_attribute_clamp.cc
Go to the documentation of this file.
1 
2 /*
3  * This program is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU General Public License
5  * as published by the Free Software Foundation; either version 2
6  * of the License, or (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software Foundation,
15  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16  */
17 
18 #include "UI_interface.h"
19 #include "UI_resources.h"
20 
21 #include "node_geometry_util.hh"
22 
24  {SOCK_GEOMETRY, N_("Geometry")},
25  {SOCK_STRING, N_("Attribute")},
26  {SOCK_STRING, N_("Result")},
27  {SOCK_VECTOR, N_("Min"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
28  {SOCK_VECTOR, N_("Max"), 1.0f, 1.0f, 1.0f, 0.0f, -FLT_MAX, FLT_MAX},
29  {SOCK_FLOAT, N_("Min"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
30  {SOCK_FLOAT, N_("Max"), 1.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
31  {SOCK_INT, N_("Min"), 0.0f, 0.0f, 0.0f, 0.0f, -100000, 100000},
32  {SOCK_INT, N_("Max"), 100.0f, 0.0f, 0.0f, 0.0f, -100000, 100000},
33  {SOCK_RGBA, N_("Min"), 0.5, 0.5, 0.5, 1.0},
34  {SOCK_RGBA, N_("Max"), 0.5, 0.5, 0.5, 1.0},
35  {-1, ""},
36 };
37 
39  {SOCK_GEOMETRY, N_("Geometry")},
40  {-1, ""},
41 };
42 
44 {
45  uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
46  uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
47 }
48 
50 {
52  __func__);
53  data->data_type = CD_PROP_FLOAT;
54  data->operation = NODE_CLAMP_MINMAX;
55  node->storage = data;
56 }
57 
59 {
60  bNodeSocket *sock_min_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 3);
61  bNodeSocket *sock_max_vector = sock_min_vector->next;
62  bNodeSocket *sock_min_float = sock_max_vector->next;
63  bNodeSocket *sock_max_float = sock_min_float->next;
64  bNodeSocket *sock_min_int = sock_max_float->next;
65  bNodeSocket *sock_max_int = sock_min_int->next;
66  bNodeSocket *sock_min_color = sock_max_int->next;
67  bNodeSocket *sock_max_color = sock_min_color->next;
68 
69  const NodeAttributeClamp &storage = *(const NodeAttributeClamp *)node->storage;
70  const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
71  nodeSetSocketAvailability(sock_min_vector, data_type == CD_PROP_FLOAT3);
72  nodeSetSocketAvailability(sock_max_vector, data_type == CD_PROP_FLOAT3);
73  nodeSetSocketAvailability(sock_min_float, data_type == CD_PROP_FLOAT);
74  nodeSetSocketAvailability(sock_max_float, data_type == CD_PROP_FLOAT);
75  nodeSetSocketAvailability(sock_min_int, data_type == CD_PROP_INT32);
76  nodeSetSocketAvailability(sock_max_int, data_type == CD_PROP_INT32);
77  nodeSetSocketAvailability(sock_min_color, data_type == CD_PROP_COLOR);
78  nodeSetSocketAvailability(sock_max_color, data_type == CD_PROP_COLOR);
79 }
80 
81 namespace blender::nodes {
82 
83 template<typename T> T clamp_value(const T val, const T min, const T max);
84 
85 template<> inline float clamp_value(const float val, const float min, const float max)
86 {
87  return std::min(std::max(val, min), max);
88 }
89 
90 template<> inline int clamp_value(const int val, const int min, const int max)
91 {
92  return std::min(std::max(val, min), max);
93 }
94 
95 template<> inline float3 clamp_value(const float3 val, const float3 min, const float3 max)
96 {
97  float3 tmp;
98  tmp.x = std::min(std::max(val.x, min.x), max.x);
99  tmp.y = std::min(std::max(val.y, min.y), max.y);
100  tmp.z = std::min(std::max(val.z, min.z), max.z);
101  return tmp;
102 }
103 
104 template<> inline Color4f clamp_value(const Color4f val, const Color4f min, const Color4f max)
105 {
106  Color4f tmp;
107  tmp.r = std::min(std::max(val.r, min.r), max.r);
108  tmp.g = std::min(std::max(val.g, min.g), max.g);
109  tmp.b = std::min(std::max(val.b, min.b), max.b);
110  tmp.a = std::min(std::max(val.a, min.a), max.a);
111  return tmp;
112 }
113 
114 template<typename T>
115 static void clamp_attribute(Span<T> read_span, MutableSpan<T> span, const T min, const T max)
116 {
117  for (const int i : span.index_range()) {
118  span[i] = clamp_value<T>(read_span[i], min, max);
119  }
120 }
121 
123  StringRef source_name,
124  StringRef result_name)
125 {
126  ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
127  if (result_attribute) {
128  return result_attribute->domain();
129  }
130  ReadAttributePtr source_attribute = component.attribute_try_get_for_read(source_name);
131  if (source_attribute) {
132  return source_attribute->domain();
133  }
134  return ATTR_DOMAIN_POINT;
135 }
136 
138 {
139  const std::string attribute_name = params.get_input<std::string>("Attribute");
140  const std::string result_name = params.get_input<std::string>("Result");
141 
142  if (attribute_name.empty() || result_name.empty()) {
143  return;
144  }
145 
146  if (!component.attribute_exists(attribute_name)) {
147  params.error_message_add(NodeWarningType::Error,
148  TIP_("No attribute with name \"") + attribute_name + "\"");
149  return;
150  }
151 
152  const NodeAttributeClamp &storage = *(const NodeAttributeClamp *)params.node().storage;
153  const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
154  const AttributeDomain domain = get_result_domain(component, attribute_name, result_name);
155  const int operation = static_cast<int>(storage.operation);
156 
157  ReadAttributePtr attribute_input = component.attribute_try_get_for_read(
158  attribute_name, domain, data_type);
159 
160  OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
161  result_name, domain, data_type);
162 
163  if (!attribute_result) {
164  params.error_message_add(NodeWarningType::Error,
165  TIP_("Could not find or create attribute with name \"") +
166  result_name + "\"");
167  return;
168  }
169 
170  switch (data_type) {
171  case CD_PROP_FLOAT3: {
172  Span<float3> read_span = attribute_input->get_span<float3>();
173  MutableSpan<float3> span = attribute_result->get_span_for_write_only<float3>();
174  float3 min = params.get_input<float3>("Min");
175  float3 max = params.get_input<float3>("Max");
176  if (operation == NODE_CLAMP_RANGE) {
177  if (min.x > max.x) {
178  std::swap(min.x, max.x);
179  }
180  if (min.y > max.y) {
181  std::swap(min.y, max.y);
182  }
183  if (min.z > max.z) {
184  std::swap(min.z, max.z);
185  }
186  }
187  clamp_attribute<float3>(read_span, span, min, max);
188  break;
189  }
190  case CD_PROP_FLOAT: {
191  Span<float> read_span = attribute_input->get_span<float>();
192  MutableSpan<float> span = attribute_result->get_span_for_write_only<float>();
193  const float min = params.get_input<float>("Min_001");
194  const float max = params.get_input<float>("Max_001");
195  if (operation == NODE_CLAMP_RANGE && min > max) {
196  clamp_attribute<float>(read_span, span, max, min);
197  }
198  else {
199  clamp_attribute<float>(read_span, span, min, max);
200  }
201  break;
202  }
203  case CD_PROP_INT32: {
204  Span<int> read_span = attribute_input->get_span<int>();
205  MutableSpan<int> span = attribute_result->get_span_for_write_only<int>();
206  const int min = params.get_input<int>("Min_002");
207  const int max = params.get_input<int>("Max_002");
208  if (operation == NODE_CLAMP_RANGE && min > max) {
209  clamp_attribute<int>(read_span, span, max, min);
210  }
211  else {
212  clamp_attribute<int>(read_span, span, min, max);
213  }
214  break;
215  }
216  case CD_PROP_COLOR: {
217  Span<Color4f> read_span = attribute_input->get_span<Color4f>();
218  MutableSpan<Color4f> span = attribute_result->get_span_for_write_only<Color4f>();
219  Color4f min = params.get_input<Color4f>("Min_003");
220  Color4f max = params.get_input<Color4f>("Max_003");
221  if (operation == NODE_CLAMP_RANGE) {
222  if (min.r > max.r) {
223  std::swap(min.r, max.r);
224  }
225  if (min.g > max.g) {
226  std::swap(min.g, max.g);
227  }
228  if (min.b > max.b) {
229  std::swap(min.b, max.b);
230  }
231  if (min.a > max.a) {
232  std::swap(min.a, max.a);
233  }
234  }
235  clamp_attribute<Color4f>(read_span, span, min, max);
236  break;
237  }
238  default: {
239  BLI_assert(false);
240  break;
241  }
242  }
243 
244  attribute_result.apply_span_and_save();
245 }
246 
248 {
249  GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
250 
251  geometry_set = geometry_set_realize_instances(geometry_set);
252 
253  if (geometry_set.has<MeshComponent>()) {
255  }
256  if (geometry_set.has<PointCloudComponent>()) {
258  }
259 
260  params.set_output("Geometry", geometry_set);
261 }
262 
263 } // namespace blender::nodes
264 
266 {
267  static bNodeType ntype;
268 
269  geo_node_type_base(&ntype, GEO_NODE_ATTRIBUTE_CLAMP, "Attribute Clamp", NODE_CLASS_ATTRIBUTE, 0);
276  &ntype, "NodeAttributeClamp", node_free_standard_storage, node_copy_standard_storage);
277  nodeRegisterType(&ntype);
278 }
AttributeDomain
Definition: BKE_attribute.h:41
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:43
void nodeSetSocketAvailability(struct bNodeSocket *sock, bool is_available)
Definition: node.cc:3726
void node_type_socket_templates(struct bNodeType *ntype, struct bNodeSocketTemplate *inputs, struct bNodeSocketTemplate *outputs)
Definition: node.cc:4527
void node_type_update(struct bNodeType *ntype, void(*updatefunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4623
void node_type_init(struct bNodeType *ntype, void(*initfunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4559
void node_type_storage(struct bNodeType *ntype, const char *storagename, void(*freefunc)(struct bNode *node), void(*copyfunc)(struct bNodeTree *dest_ntree, struct bNode *dest_node, const struct bNode *src_node))
Definition: node.cc:4599
#define NODE_CLASS_ATTRIBUTE
Definition: BKE_node.h:360
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1298
#define BLI_assert(a)
Definition: BLI_assert.h:58
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define UNUSED(x)
#define TIP_(msgid)
#define N_(msgid)
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:126
void swap(T &a, T &b)
Definition: Common.h:33
CustomDataType
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
@ CD_PROP_COLOR
@ CD_PROP_INT32
@ NODE_CLAMP_RANGE
@ NODE_CLAMP_MINMAX
@ SOCK_INT
@ SOCK_VECTOR
@ SOCK_FLOAT
@ SOCK_GEOMETRY
@ SOCK_STRING
@ SOCK_RGBA
Group RGB to Bright Vector Camera Vector Combine Material Light Line Style Layer Add Ambient Diffuse Glossy Refraction Transparent Toon Principled Hair Volume Principled Light Particle Volume Image Sky Noise Wave Voronoi Brick Texture Vector Combine Vertex Separate Vector White RGB Map Separate Set Z Dilate Combine Combine Color Channel Split ID Combine Luminance Directional Alpha Distance Hue Movie Ellipse Bokeh View Corner Anti Mix RGB Hue Separate TEX_NODE_PROC TEX_NODE_PROC TEX_NODE_PROC TEX_NODE_PROC TEX_NODE_PROC Boolean Random Edge Subdivision Point Object Attribute Attribute Attribute Color Attribute Attribute Vector Point Attribute Sample Collection Attribute Attribute Combine Attribute GEO_NODE_ATTRIBUTE_CLAMP
#define C
Definition: RandGen.cpp:39
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
constexpr IndexRange index_range() const
Definition: BLI_span.hh:659
fn::GMutableSpan get_span_for_write_only()
OperationNode * node
void * tree
bNodeTree * ntree
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
#define T
GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set)
std::unique_ptr< ReadAttribute > ReadAttributePtr
T clamp_value(const T val, const T min, const T max)
static void geo_node_attribute_clamp_exec(GeoNodeExecParams params)
static AttributeDomain get_result_domain(const GeometryComponent &component, StringRef source_name, StringRef result_name)
static void clamp_attribute(Span< T > read_span, MutableSpan< T > span, const T min, const T max)
static bNodeSocketTemplate geo_node_attribute_clamp_in[]
static bNodeSocketTemplate geo_node_attribute_clamp_out[]
static void geo_node_attribute_clamp_init(bNodeTree *UNUSED(tree), bNode *node)
void register_node_type_geo_attribute_clamp()
static void geo_node_attribute_clamp_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void geo_node_attribute_clamp_update(bNodeTree *UNUSED(ntree), bNode *node)
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
void node_copy_standard_storage(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node)
Definition: node_util.c:67
void node_free_standard_storage(bNode *node)
Definition: node_util.c:55
#define min(a, b)
Definition: sort.c:51
GeometryComponent & get_component_for_write(GeometryComponentType component_type)
bool has(const GeometryComponentType component_type) const
Compact definition of a node socket.
Definition: BKE_node.h:95
struct bNodeSocket * next
Defines a node type.
Definition: BKE_node.h:221
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:327
void(* draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr)
Definition: BKE_node.h:253
float max
PointerRNA * ptr
Definition: wm_files.c:3157