HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SOP_SplitPointsHDK.C
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2021
3  * Side Effects Software Inc. All rights reserved.
4  *
5  * Redistribution and use of Houdini Development Kit samples in source and
6  * binary forms, with or without modification, are permitted provided that the
7  * following conditions are met:
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. The name of Side Effects Software may not be used to endorse or
11  * promote products derived from this software without specific prior
12  * written permission.
13  *
14  * THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE `AS IS' AND ANY EXPRESS
15  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
17  * NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
20  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
23  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  *----------------------------------------------------------------------------
26  * This SOP splits points, optionally limited based on differences in vertex
27  * or primitive attributes.
28  */
29 
30 #include "SOP_SplitPointsHDK.proto.h"
31 
32 #include "GEO_SplitPoints.h"
33 
34 #include <SOP/SOP_Node.h>
35 #include <GU/GU_Detail.h>
36 #include <GU/GU_Promote.h>
37 #include <PRM/PRM_Include.h>
39 #include <UT/UT_Assert.h>
40 #include <UT/UT_DSOVersion.h>
41 
42 namespace HDK_Sample {
43 
44 //******************************************************************************
45 //* Setup *
46 //******************************************************************************
47 
49 {
50 public:
53 
54  virtual SOP_NodeParms *allocParms() const { return new SOP_SplitPointsHDKParms(); }
55  virtual UT_StringHolder name() const { return theSOPTypeName; }
56 
57  virtual CookMode cookMode(const SOP_NodeParms *parms) const { return COOK_INPLACE; }
58 
59  virtual void cook(const CookParms &cookparms) const;
60 
61  /// This is the internal name of the SOP type.
62  /// It isn't allowed to be the same as any other SOP's type name.
64 
65  /// This static data member automatically registers
66  /// this verb class at library load time.
68 
69  /// This is the parameter interface string, below.
70  static const char *const theDsFile;
71 };
72 
73 // The static member variable definitions have to be outside the class definition.
74 // The declarations are inside the class.
77 
78 /// This is the SOP class definition.
80 {
81 public:
82  SOP_SplitPointsHDK(OP_Network *net, const char *, OP_Operator *entry);
83  virtual ~SOP_SplitPointsHDK();
84 
85  virtual OP_ERROR cookInputGroups(OP_Context &context, int alone);
86 
87  static OP_Node *myConstructor(OP_Network *net, const char *name, OP_Operator *entry);
88  static PRM_Template *buildTemplates();
89  virtual const SOP_NodeVerb *cookVerb() const;
90 
91  static void buildAttribMenu(
92  void *data, PRM_Name *entries, int size,
93  const PRM_SpareData *, const PRM_Parm *);
94 
95  virtual OP_ERROR cookMySop(OP_Context &context);
96 };
97 
98 static GA_GroupType
99 sopSplitPointsGroupType(SOP_SplitPointsHDKParms::GroupType parmgrouptype)
100 {
101  using namespace SOP_SplitPointsHDKEnums;
102  switch (parmgrouptype)
103  {
104  case GroupType::GUESS: return GA_GROUP_INVALID; break;
105  case GroupType::POINTS: return GA_GROUP_POINT; break;
106  case GroupType::PRIMS: return GA_GROUP_PRIMITIVE; break;
107  case GroupType::VERTICES: return GA_GROUP_VERTEX; break;
108  }
109  UT_ASSERT_MSG(0, "Unhandled group type!");
110  return GA_GROUP_INVALID;
111 }
112 
113 void
115  void *data, PRM_Name *entries, int size,
116  const PRM_SpareData *, const PRM_Parm *)
117 {
118  SOP_SplitPointsHDK *sop = (SOP_SplitPointsHDK *)data;
119  if (!sop)
120  return;
121 
122  const int input = 0; // input from which to obtain attribs
123 
124  sop->fillAttribNameMenu(entries, size, GA_ATTRIB_VERTEX, input);
125 }
126 static PRM_ChoiceList sop_attribmenu(
129 
132 {
133  static PRM_TemplateBuilder templ("SOP_SplitPointsHDK.C"_sh, SOP_SplitPointsHDKVerb::theDsFile);
134  if (templ.justBuilt())
135  {
137  templ.setChoiceListPtr("attribname", &sop_attribmenu);
138  }
139  return templ.templates();
140 }
141 
142 OP_Node *
144 {
145  return new SOP_SplitPointsHDK(net, name, entry);
146 }
147 
148 
150  : SOP_Node(net, name, entry)
151 {
153 }
154 
156 {}
157 
158 OP_ERROR
160 {
161  UT_ASSERT(alone);
162 
163  GA_GroupType grouptype = sopSplitPointsGroupType(
164  (SOP_SplitPointsHDKEnums::GroupType)evalInt("grouptype"_sh, 0, context.getTime()));
165 
166  const GA_Group *group;
168  context,
169  group,
170  alone != 0,
171  true, // do_selection
172  0, // group parm index
173  1, // group type parm index
174  grouptype,
175  true, // allow_reference
176  false // is_default_prim
177  );
178  return error();
179 }
180 
181 OP_ERROR
183 {
184  return cookMyselfAsVerb(context);
185 }
186 
187 const SOP_NodeVerb *
189 {
190  return SOP_SplitPointsHDKVerb::theVerb.get();
191 }
192 
193 } // End of HDK_Sample namespace
194 
195 /// newSopOperator is the hook that Houdini grabs from this dll
196 /// and invokes to register the SOP. In this case, we add ourselves
197 /// to the specified operator table.
199 {
200  table->addOperator(new OP_Operator(
202  "HDK Split Points", // UI name
203  HDK_Sample::SOP_SplitPointsHDK::myConstructor, // How to build the SOP
205  1, // Min # of sources
206  1, // Max # of sources
207  nullptr,// Custom local variables (none)
208  0)); // No flags: not a generator, no merge input, not an output
209 }
210 
211 namespace HDK_Sample {
212 
213 //******************************************************************************
214 //* Parameters *
215 //******************************************************************************
216 
217 /// This is a multi-line raw string specifying the parameter interface for this SOP.
218 const char *const SOP_SplitPointsHDKVerb::theDsFile = R"THEDSFILE(
219 {
220  name parameters
221  parm {
222  name "group"
223  label "Group"
224  type string
225  default { "" }
226  parmtag { "script_action" "import soputils\nkwargs['geometrytype'] = kwargs['node'].parmTuple('grouptype')\nkwargs['inputindex'] = 0\nsoputils.selectGroupParm(kwargs)" }
227  parmtag { "script_action_help" "Select geometry from an available viewport.\nShift-click to turn on Select Groups." }
228  parmtag { "script_action_icon" "BUTTONS_reselect" }
229  }
230  parm {
231  name "grouptype"
232  cppname "GroupType"
233  label "Group Type"
234  type ordinal
235  default { "0" }
236  menu {
237  "guess" "Guess from Group"
238  "vertices" "Vertices"
239  "points" "Points"
240  "prims" "Primitives"
241  }
242  }
243  parm {
244  name "useattrib"
245  cppname "UseAttrib"
246  label "Limit by Attribute"
247  type toggle
248  default { "0" }
249  nolabel
250  joinnext
251  }
252  parm {
253  name "attribname"
254  cppname "AttribName"
255  label "Attributes"
256  type string
257  default { "N" }
258  disablewhen "{ useattrib == 0 }"
259  }
260  parm {
261  name "tol"
262  label "Tolerance"
263  type log
264  default { "0.001" }
265  range { 0! 1 }
266  disablewhen "{ useattrib == 0 }"
267  }
268  parm {
269  name "promote"
270  label "Promote to Point Attribute"
271  type toggle
272  default { "0" }
273  disablewhen "{ useattrib == 0 }"
274  }
275 }
276 )THEDSFILE";
277 
278 
279 void
281 {
282  auto &&sopparms = cookparms.parms<SOP_SplitPointsHDKParms>();
283  GU_Detail *gdp = cookparms.gdh().gdpNC();
284  GOP_Manager gop;
285 
286  const GA_ElementGroup *group = nullptr;
287 
288  const UT_StringHolder &groupname = sopparms.getGroup();
289  if (groupname.isstring())
290  {
291  GA_GroupType grouptype = sopSplitPointsGroupType(sopparms.getGroupType());
292 
293  bool ok = true;
294  const GA_Group *anygroup = gop.parseGroupDetached(groupname, grouptype, gdp, true, false, ok);
295 
296  if (!ok || (anygroup && !anygroup->isElementGroup()))
297  {
298  cookparms.sopAddWarning(SOP_ERR_BADGROUP, groupname);
299  }
300  if (anygroup && anygroup->isElementGroup())
301  {
302  group = UTverify_cast<const GA_ElementGroup *>(anygroup);
303  }
304  }
305  notifyGroupParmListeners(cookparms.getNode(), 0, 1, gdp, group);
306 
307  if (sopparms.getUseAttrib() && sopparms.getAttribName().isstring())
308  {
309  fpreal tolerance = sopparms.getTol();
310  const bool promote = sopparms.getPromote();
311 
312  const char *pattern = sopparms.getAttribName().c_str();
313  if (UT_String::multiMatchCheck(pattern))
314  {
315  UT_StringArray attribsToPromote;
316  auto &&functor = [pattern,promote,gdp,group,tolerance,&attribsToPromote](GA_Attribute *attrib)
317  {
318  UT_String attribname_string(attrib->getName().c_str());
319  if (!attribname_string.multiMatch(pattern))
320  return;
321 
322  // NOTE: This will bump any data IDs as needed, if any points are split.
323  GEOsplitPointsByAttrib(gdp, group, attrib, tolerance);
324 
325  if (promote)
326  {
327  // Don't promote the attributes while iterating over them
328  attribsToPromote.append(attrib->getName());
329  }
330  };
331 
332  // NOTE: The iteration order must be alphabetical, instead of
333  // the hash table order, for consistency.
334  for (auto it = gdp->vertexAttribs().obegin(GA_SCOPE_PUBLIC); !it.atEnd(); ++it)
335  functor(it.item());
336  for (exint i = 0; i < attribsToPromote.size(); ++i)
337  {
338  GA_Attribute *attrib = gdp->findAttribute(GA_ATTRIB_VERTEX, GA_SCOPE_PUBLIC, attribsToPromote[i]);
339  if (attrib)
341  }
342  attribsToPromote.clear();
343 
344  for (auto it = gdp->primitiveAttribs().obegin(GA_SCOPE_PUBLIC); !it.atEnd(); ++it)
345  functor(it.item());
346  for (exint i = 0; i < attribsToPromote.size(); ++i)
347  {
348  GA_Attribute *attrib = gdp->findAttribute(GA_ATTRIB_PRIMITIVE, GA_SCOPE_PUBLIC, attribsToPromote[i]);
349  if (attrib)
351  }
352  attribsToPromote.clear();
353 
354  for (auto it = gdp->vertexAttribs().obegin(GA_SCOPE_GROUP); !it.atEnd(); ++it)
355  functor(it.item());
356  for (exint i = 0; i < attribsToPromote.size(); ++i)
357  {
358  GA_ElementGroup *cur_group = gdp->findVertexGroup(attribsToPromote[i]);
359  if (cur_group && !cur_group->isInternal())
361  }
362  attribsToPromote.clear();
363 
364  for (auto it = gdp->primitiveAttribs().obegin(GA_SCOPE_GROUP); !it.atEnd(); ++it)
365  functor(it.item());
366  for (exint i = 0; i < attribsToPromote.size(); ++i)
367  {
368  GA_ElementGroup *cur_group = gdp->findPrimitiveGroup(attribsToPromote[i]);
369  if (cur_group && !cur_group->isInternal())
371  }
372  attribsToPromote.clear();
373  }
374  else
375  {
376  GA_Attribute *attrib = gdp->vertexAttribs().find(GA_SCOPE_PUBLIC, sopparms.getAttribName());
377  if (!attrib)
378  {
379  attrib = gdp->primitiveAttribs().find(GA_SCOPE_PUBLIC, sopparms.getAttribName());
380  if (!attrib)
381  {
382  // The attribute should be able to be a group, so that we
383  // can easily split along group boundaries.
384  attrib = gdp->vertexGroups().find(sopparms.getAttribName());
385  if (!attrib)
386  {
387  attrib = gdp->primitiveGroups().find(sopparms.getAttribName());
388  if (!attrib)
389  {
390  cookparms.sopAddWarning(SOP_MESSAGE, "Couldn't find specified vertex or primitive attribute");
391  return;
392  }
393  }
394  }
395  }
396 
397  // NOTE: This will bump any data IDs as needed, if any points are split.
398  GEOsplitPointsByAttrib(gdp, group, attrib, tolerance);
399 
400  if (promote)
401  {
403  }
404  }
405  }
406  else if (!sopparms.getUseAttrib())
407  {
408  // NOTE: This will bump any data IDs as needed, if any points are split.
409  GEOsplitPoints(gdp, group);
410  }
411 }
412 
413 } // End of HDK_Sample namespace
Definition of a geometry attribute.
Definition: GA_Attribute.h:196
GLenum GLenum GLenum input
Definition: glew.h:13879
GLsizeiptr size
Definition: glew.h:1681
SOP_Node * getNode() const
Definition: SOP_NodeVerb.h:640
GLuint const GLchar * name
Definition: glew.h:1814
virtual OP_ERROR error()
void setChoiceListPtr(const UT_StringRef &name, PRM_ChoiceList *list)
UT_ErrorSeverity sopAddWarning(int code, const char *msg=0, const UT_SourceLocation *loc=0) const
Definition: SOP_NodeVerb.h:723
static PRM_Template * buildTemplates()
fpreal getTime() const
Definition: OP_Context.h:60
GLenum GLsizei GLenum GLenum const void * table
Definition: glew.h:4940
int64 exint
Definition: SYS_Types.h:125
virtual OP_ERROR cookInputGroups(OP_Context &context, int alone)
const GA_Group * parseGroupDetached(const char *pat, GA_GroupType grouptype, const GEO_Detail *pgdp, bool forceexistence, bool defaultprim, bool &success)
UT_ErrorSeverity
Definition: UT_Error.h:25
GA_Size GEOsplitPointsByAttrib(GEO_Detail *detail, const GA_ElementGroup *group, const GA_Attribute *attrib, fpreal tolerance)
static const char *const theDsFile
This is the parameter interface string, below.
static const SOP_NodeVerb::Register< SOP_SplitPointsHDKVerb > theVerb
PRM_ChoiceListType
SYS_FORCE_INLINE TO_T UTverify_cast(FROM_T from)
Definition: UT_Assert.h:208
int fillAttribNameMenu(PRM_Name *menu_entries, int max_menu_size, GA_AttributeOwner dictionary, int input_index, bool(*approve)(const GA_Attribute *, void *)=NULL, void *approve_data=NULL)
bool addOperator(OP_Operator *op, std::ostream *err=nullptr)
Standard user attribute level.
Definition: GA_Types.h:147
virtual CookMode cookMode(const SOP_NodeParms *parms) const
static PRM_ChoiceList pointGroupMenu
Definition: SOP_Node.h:1178
exint size() const
Definition: UT_Array.h:458
#define UT_ASSERT_MSG(ZZ,...)
Definition: UT_Assert.h:138
static GA_Attribute * promote(GU_Detail &gdp, GA_Attribute *attrib, GA_AttributeOwner new_owner, bool destroy_existing=true, PROMOTE_METHOD method=GU_PROMOTE_MEAN, const char *new_name=NULL, const GA_Attribute *piece_attrib=nullptr)
const T & parms() const
Definition: SOP_NodeVerb.h:690
Constructs a PRM_Template list from an embedded .ds file or an istream.
GLint GLenum GLsizei GLint GLsizei const void * data
Definition: glew.h:1379
PRM_Template * templates() const
bool isElementGroup() const
Definition: GA_Group.h:63
OP_ERROR cookMyselfAsVerb(OP_Context &context)
static void buildAttribMenu(void *data, PRM_Name *entries, int size, const PRM_SpareData *, const PRM_Parm *)
SOP_NodeFlags mySopFlags
Definition: SOP_Node.h:1633
bool isInternal() const
Definition: GA_Group.h:45
void newSopOperator(OP_OperatorTable *table)
GU_Detail * gdpNC()
void setManagesDataIDs(bool onOff)
Definition: SOP_NodeFlags.h:34
exint append()
Definition: UT_Array.h:95
static bool multiMatchCheck(const char *pattern)
void notifyGroupParmListeners(SOP_Node *oldsop, int groupparm_idx, int grouptype_idx, const GU_Detail *gdp, const GA_Group *group) const
static const UT_StringHolder theSOPTypeName
virtual const SOP_NodeVerb * cookVerb() const
OP_ERROR cookInputAllGroups(OP_Context &context, const GA_Group *&group, bool alone=false, bool do_selection=true, int parm_index=0, int group_type_index=-1, GA_GroupType grouptype=GA_GROUP_INVALID, bool allow_reference=true, bool is_default_prim=true, bool ordered=false, bool detached=true, int input_index=0)
fpreal64 fpreal
Definition: SYS_Types.h:277
static OP_Node * myConstructor(OP_Network *net, const char *name, OP_Operator *entry)
GA_GroupType
An ordinal enum for the different types of groups in GA.
Definition: GA_Types.h:159
This is the SOP class definition.
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:135
GA_Size GEOsplitPoints(GEO_Detail *detail, const GA_ElementGroup *group)
SOP_SplitPointsHDK(OP_Network *net, const char *, OP_Operator *entry)
exint evalInt(int pi, int vi, fpreal t) const
virtual SOP_NodeParms * allocParms() const
GLubyte * pattern
Definition: glew.h:5711
void clear()
Resets list to an empty list.
Definition: UT_Array.h:528
virtual OP_ERROR cookMySop(OP_Context &context)
virtual void cook(const CookParms &cookparms) const
Compute the output geometry.
GU_DetailHandle & gdh() const
The initial state of gdh depends on the cookMode()
Definition: SOP_NodeVerb.h:634
SYS_FORCE_INLINE bool isstring() const
GLboolean GLuint group
Definition: glew.h:2745
virtual UT_StringHolder name() const