HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SOP_CustomBrush.C
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2024
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  */
27 
28 #include "SOP_CustomBrush.h"
29 
30 #include <GA/GA_Handle.h>
31 #include <GA/GA_Types.h>
32 #include <OP/OP_AutoLockInputs.h>
33 #include <OP/OP_OperatorTable.h>
34 #include <OP/OP_SaveFlags.h>
35 #include <PRM/PRM_Include.h>
36 #include <UT/UT_CPIO.h>
37 #include <UT/UT_DSOVersion.h>
38 #include <UT/UT_IStream.h>
39 #include <UT/UT_Map.h>
40 #include <UT/UT_OStream.h>
41 #include <UT/UT_Undo.h>
42 #include <UT/UT_UndoManager.h>
43 #include <UT/UT_Vector3.h>
44 #include <SYS/SYS_Types.h>
45 #include <stddef.h>
46 
47 // undo for CustomBrush
48 namespace HDK_Sample {
50 {
51 public:
53  GA_Size oldnumpts,
54  GA_Size numpts,
57 
58  void undo() override;
59  void redo() override;
60 
61 private:
62  int mySopId;
63  GA_Size myOldNumPts;
64  GA_Size myNumPts;
67 };
68 } // End HDK_Sample namespace
69 using namespace HDK_Sample;
70 
72  SOP_CustomBrush *sop,
73  GA_Size oldnumpts,
74  GA_Size numpts,
77  mySopId(sop->getUniqueId()),
78  myOldNumPts(oldnumpts),
79  myNumPts(numpts),
80  myOldData(olddata),
81  myData(data)
82 {
83  // include the memory allocated by the UT_RefArrays to accurately compute
84  // the total memory used by this undo
86 }
87 
88 void
90 {
92  node->updateData(myOldNumPts, myOldData);
93 }
94 
95 void
97 {
99  node->updateData(myNumPts, myData);
100 }
101 
102 void
104 {
105  table->addOperator(new OP_Operator("proto_custombrush", "Custom Brush",
108  1, 1));
109 }
110 
111 static PRM_Name sopOriginName("origin", "Origin");
112 static PRM_Name sopDirectionName("direction", "Direction");
113 static PRM_Name sopRadiusName("radius", "Radius");
114 static PRM_Name sopColorName("color", "Color");
115 static PRM_Name sopAlphaName("alpha", "Alpha");
116 static PRM_Name sopOperationName("operation", "Operation");
117 static PRM_Name sopEventName("event", "Event");
118 static PRM_Name sopClearAllName("clearall", "Clear All");
119 
121 {
124 };
125 
126 static PRM_Name sopOperationMenuNames[] =
127 {
128  PRM_Name("paint", "Paint"),
129  PRM_Name("erase", "Erase"),
130  PRM_Name(0)
131 };
132 static PRM_ChoiceList sopOperationMenu(PRM_CHOICELIST_SINGLE, sopOperationMenuNames);
133 static PRM_Default sopOperationDefault(SOP_CUSTOMBRUSHOPERATION_PAINT);
134 
136 {
141 };
142 
143 static PRM_Name sopEventMenuNames[] =
144 {
145  PRM_Name("begin", "Begin Stroke"),
146  PRM_Name("active", "Active Stroke"),
147  PRM_Name("end", "End Stroke"),
148  PRM_Name("nop", "No-op"),
149  PRM_Name(0)
150 };
151 static PRM_ChoiceList sopEventMenu(PRM_CHOICELIST_SINGLE, sopEventMenuNames);
152 static PRM_Default sopEventDefault(SOP_CUSTOMBRUSHEVENT_NOP);
153 
158  GA_GROUP_POINT)),
159  PRM_Template(PRM_XYZ_J, 3, &sopOriginName),
160  PRM_Template(PRM_XYZ_J, 3, &sopDirectionName),
161  PRM_Template(PRM_FLT_J, 1, &sopRadiusName, PRMoneDefaults),
162  PRM_Template(PRM_RGB_J, 3, &sopColorName, PRMoneDefaults),
163  PRM_Template(PRM_FLT_J, 1, &sopAlphaName, PRMpointOneDefaults),
164  PRM_Template(PRM_ORD, 1, &sopOperationName, &sopOperationDefault,
165  &sopOperationMenu),
166  PRM_Template(PRM_ORD, 1, &sopEventName, &sopEventDefault, &sopEventMenu),
167  PRM_Template(PRM_CALLBACK, 1, &sopClearAllName, 0, 0, 0, &clearAllStatic),
168  PRM_Template()
169 };
170 
171 OP_Node *
173 {
174  return new SOP_CustomBrush(net, name, op);
175 }
176 
178  SOP_Node(net, name, op),
179  myGroup(0),
180  myNumPts(0),
181  myOldNumPts(0)
182 {
183  // This indicates that this SOP manually manages its data IDs,
184  // so that Houdini can identify what attributes may have changed,
185  // e.g. to reduce work for the viewport, or other SOPs that
186  // check whether data IDs have changed.
187  // By default, (i.e. if this line weren't here), all data IDs
188  // would be bumped after the SOP cook, to indicate that
189  // everything might have changed.
190  // If some data IDs don't get bumped properly, the viewport
191  // may not update, or SOPs that check data IDs
192  // may not cook correctly, so be *very* careful!
194 }
195 
197 {
198 }
199 
200 OP_ERROR
202 {
203  // The SOP_Node::cookInputPointGroups() provides a good default
204  // implementation for just handling a point selection.
205  return cookInputPointGroups(
206  context, // This is needed for cooking the group parameter, and cooking the input if alone.
207  myGroup, // The group (or NULL) is written to myGroup if not alone.
208  alone, // This is true iff called outside of cookMySop to update handles.
209  // true means the group will be for the input geometry.
210  // false means the group will be for gdp (the working/output geometry).
211  true, // (default) true means to set the selection to the group if not alone and the highlight flag is on.
212  0, // (default) Parameter index of the group field
213  -1, // (default) Parameter index of the group type field (-1 since there isn't one)
214  true, // (default) true means that a pointer to an existing group is okay; false means group is always new.
215  false, // (default) false means new groups should be unordered; true means new groups should be ordered.
216  true, // (default) true means that all new groups should be detached, so not owned by the detail;
217  // false means that new point and primitive groups on gdp will be owned by gdp.
218  0 // (default) Index of the input whose geometry the group will be made for if alone.
219  );
220 }
221 
222 OP_ERROR
224 {
225  // We must lock our inputs before we try to access their geometry.
226  // OP_AutoLockInputs will automatically unlock our inputs when we return.
227  // NOTE: Don't call unlockInputs yourself when using this!
228  OP_AutoLockInputs inputs(this);
229  if (inputs.lock(context) >= UT_ERROR_ABORT)
230  return error();
231 
232  fpreal t = context.getTime();
233 
234  // make a copy of input 0's geometry if it different from our last
235  // cook
236  int changed_input;
237  duplicateChangedSource(0, context, &changed_input);
238 
239  if (cookInputGroups(context) >= UT_ERROR_ABORT)
240  return error();
241 
242  GA_Size npts = gdp->getNumPoints();
243 
244  if(myData.size() == 0)
245  {
246  // we have no paint yet, when we apply additional paint we will
247  // require there to be 'npts' points
248  myNumPts = npts;
249  }
250  else if(myNumPts != npts)
251  {
252  // we cannot apply the paint as the point numbers have changed
254  return error();
255  }
256 
257  int event = getEvent(t);
259  {
260  // we are starting a new brush stroke
261  myOldData.setSize(0);
262  myOldNumPts = myNumPts;
263  }
265  {
266  // we are in the middle of performing a brush stroke
267  UT_Vector3 origin = getOrigin(t);
268  UT_Vector3 direction = getDirection(t);
269  direction.normalize();
270  fpreal radius = getRadius(t);
271  fpreal radius2 = radius * radius;
272  fpreal alpha = getBrushAlpha(t);
273  UT_Vector3 color = getBrushColor(t);
274  int operation = getOperation(t);
275 
276  // build lookup table from a point number to the paint applied to
277  // that point
279  for(exint i = 0; i < myData.size(); ++i)
280  table[myData(i).myPtNum] = i;
281  UT_Map<GA_Index,exint> oldtable;
282  for(exint i = 0; i < myOldData.size(); ++i)
283  oldtable[myOldData(i).myPtNum] = i;
284 
285  GA_Offset ptoff;
286  GA_FOR_ALL_GROUP_PTOFF(gdp, myGroup, ptoff)
287  {
288  // determine if we should apply paint to this point
289 
290  UT_Vector3 pos = gdp->getPos3(ptoff);
291 
292  UT_Vector3 p = pos - origin;
293  p.normalize();
294  fpreal dot_p_dir = dot(p, direction);
295  if (dot_p_dir <= 0)
296  continue;
297 
298  UT_Vector3 par = dot_p_dir * direction;
299  UT_Vector3 perp = p - par;
300 
301  fpreal parlen2 = dot_p_dir * dot_p_dir;
302  if (parlen2 <= 0 || perp.length2() >= radius2 * parlen2)
303  continue;
304 
305  // we will apply paint to this point
306  GA_Index ptnum = gdp->pointIndex(ptoff);
307 
308  // find the current amount of applied paint
309  auto it = table.find(ptnum);
310  exint index;
311  if (it == table.end())
312  {
313  // no paint has been applied yet
314  index = myData.append(SOP_CustomBrushData(ptnum, 0, 0, 0, 0));
315  table[ptnum] = index;
316  }
317  else
318  index = it->second;
319  SOP_CustomBrushData &d = myData(index);
320 
321  auto oldit = oldtable.find(ptnum);
322  if (oldit == oldtable.end())
323  {
324  // remember the old paint value for undos
325  index = myOldData.append(d);
326  oldtable[ptnum] = index;
327  }
328 
329  // update the paint value
330  fpreal one_minus_alpha = 1 - alpha;
331  switch(operation)
332  {
334  d.myRed = alpha * color.x() + one_minus_alpha * d.myRed;
335  d.myGreen = alpha * color.y() + one_minus_alpha * d.myGreen;
336  d.myBlue = alpha * color.z() + one_minus_alpha * d.myBlue;
337  d.myAlpha = alpha + one_minus_alpha * d.myAlpha;
338  break;
339 
341  d.myRed *= one_minus_alpha;
342  d.myGreen *= one_minus_alpha;
343  d.myBlue *= one_minus_alpha;
344  d.myAlpha *= one_minus_alpha;
345  break;
346  }
347  }
348  }
349  else if(event == SOP_CUSTOMBRUSHEVENT_END)
350  {
351  // we have finished performing a brush stroke
353  if(man->willAcceptUndoAddition())
354  {
355  // create an undo for the entire brush stroke
356  man->addToUndoBlock(new SOP_UndoCustomBrushData(this, myOldNumPts, myNumPts, myOldData, myData));
357  myOldData.setSize(0);
358  }
359  }
360 
361  // find the color attribute in the original geometry
362  const GU_Detail *input0 = inputGeo(0);
363  GA_ROHandleV3 input_handle(input0->findFloatTuple(GA_ATTRIB_POINT,
365 
366  // find the color attribute in the current geometry, creating one
367  // if necessary
370  if (!handle.isValid())
371  {
374  }
375 
376  // update the colour for all painted points
377  for (exint i = 0; i < myData.size(); ++i)
378  {
379  SOP_CustomBrushData &data = myData(i);
380 
381  fpreal r = data.myRed;
382  fpreal g = data.myGreen;
383  fpreal b = data.myBlue;
384  if (input_handle.isValid())
385  {
386  fpreal one_minus_alpha = 1 - data.myAlpha;
387  GA_Offset ptoff = input0->pointOffset(data.myPtNum);
388  UT_Vector3 f = input_handle.get(ptoff);
389  r += one_minus_alpha * f.x();
390  g += one_minus_alpha * f.y();
391  b += one_minus_alpha * f.z();
392  }
393 
394  GA_Offset ptoff = gdp->pointOffset(data.myPtNum);
395  handle.set(ptoff, UT_Vector3(r, g, b));
396  }
397 
398  if (myData.size() > 0)
399  handle.bumpDataId();
400 
401  return error();
402 }
403 
404 OP_ERROR
406  std::ostream &os,
407  const OP_SaveFlags &saveflags,
408  const char *path_prefix,
409  const UT_String &name_override)
410 {
411  if(SOP_Node::save(os, saveflags, path_prefix, name_override) >= UT_ERROR_ABORT)
412  return error();
413 
414  // create a new packet for our paint
415  UT_CPIO packet;
417  const char *ext = saveflags.getBinary() ? "bpaint" : "paint";
418  path.sprintf("%s%s.%s", path_prefix, (const char *)getName(), ext);
419  packet.open(os, path.buffer());
420  {
421  UT_OStream out(os, saveflags.getBinary());
422 
423  out.write(&myNumPts, 1, true);
424 
425  exint n = myData.size();
426  out.write(&n, 1, true);
427 
428  for (exint i = 0; i < n; ++i)
429  {
430  SOP_CustomBrushData &data = myData(i);
431  out.write((GA_Size *)&data.myPtNum);
432  out.write<fpreal32>(&data.myRed);
433  out.write<fpreal32>(&data.myGreen);
434  out.write<fpreal32>(&data.myBlue);
435  out.write<fpreal32>(&data.myAlpha, 1, (i == n - 1));
436  }
437  }
438  packet.close(os);
439 
440  return error();
441 }
442 
443 bool
444 SOP_CustomBrush::load(UT_IStream &is, const char *ext, const char *path)
445 {
446  // update our paint values if this is a paint packet
447  if(strcmp(ext, "bpaint") == 0 || strcmp(ext, "paint") == 0)
448  {
449  myNumPts = 0;
450  myData.setSize(0);
451  myOldData.setSize(0);
452 
453  if(!is.read(&myNumPts))
454  return false;
455 
456  exint n;
457  if(!is.read(&n))
458  return false;
459  for(exint i = 0; i < n; ++i)
460  {
461  GA_Size idx;
462  if(!is.read(&idx))
463  return false;
464 
465  float r;
466  if(!is.read<fpreal32>(&r))
467  return false;
468 
469  float g;
470  if(!is.read<fpreal32>(&g))
471  return false;
472 
473  float b;
474  if(!is.read<fpreal32>(&b))
475  return false;
476 
477  float a;
478  if(!is.read<fpreal32>(&a))
479  return false;
480 
481  myData.append(SOP_CustomBrushData(idx, r, g, b, a));
482  }
483 
484  return true;
485  }
486 
487  return SOP_Node::load(is, ext, path);
488 }
489 
490 void
492 {
493  myNumPts = numpts;
494  if (myNumPts == 0)
495  {
496  myData.setSize(0);
497 
498  // we make the SOP think the input geometry has changed so it will
499  // duplicate the input geometry to reset the attribute values. This
500  // is necessary as our cook method only modified the color attribute
501  // of points indicated by myData, which is now empty.
503  }
504  else
505  {
506  // build lookup table from a point number to the paint applied to
507  // that point
509  for (exint i = 0; i < myData.size(); ++i)
510  table[myData(i).myPtNum] = i;
511 
512  for (exint i = 0; i < data.size(); ++i)
513  {
514  SOP_CustomBrushData &d = data(i);
515 
516  UT_Map<GA_Index,exint>::iterator it = table.find(d.myPtNum);
517  if(it != table.end())
518  {
519  // we already have paint applied to this point, just update the
520  // paint values
521  myData(it->second) = d;
522  }
523  else
524  {
525  // create a new entry for the paint
526  exint index = myData.append(d);
527  table[d.myPtNum] = index;
528  }
529  }
530  }
531 
532  // tell our SOP to re-cook as we have changed the paint values
533  forceRecook();
534 }
535 
536 int
538 {
539  SOP_CustomBrush *sop = (SOP_CustomBrush *)op;
540  sop->clearAll();
541  return 1;
542 }
543 
544 void
546 {
547  UT_AutoUndoBlock undoblock("Clear All", ANYLEVEL);
548 
549  GA_Size oldnumpts = myNumPts;
550  myNumPts = 0;
551  myOldData = myData;
552  myData.setSize(0);
553 
555  if (man->willAcceptUndoAddition())
556  {
557  man->addToUndoBlock(new SOP_UndoCustomBrushData(this, oldnumpts, myNumPts, myOldData, myData));
558  myOldData.setSize(0);
559  }
560 
561  // we make the SOP think the input geometry has changed so it will
562  // duplicate the input geometry to reset the attribute values. This is
563  // necessary as our cook method only modified the color attribute of
564  // points indicated by myData, which is now empty.
566  forceRecook();
567 }
constexpr SYS_FORCE_INLINE T length2() const noexcept
Definition: UT_Vector3.h:356
virtual int open(UT_IStream &is, UT_WorkBuffer &pathname)
#define GEO_STD_ATTRIB_DIFFUSE
Definition: GEO_Detail.h:100
PRM_API const PRM_Type PRM_CALLBACK
virtual OP_ERROR error()
static int clearAllStatic(void *op, int, fpreal time, const PRM_Template *)
bool getBinary() const
Definition: OP_SaveFlags.h:20
PRM_API const PRM_Type PRM_STRING
UT_OStream & write(const char_type *str, int64 count)
Definition: UT_OStream.h:348
OP_ERROR lock(OP_Context &context)
Locks all inputs.
GLboolean * data
Definition: glcorearb.h:131
GA_Attribute * addFloatTuple(GA_AttributeOwner owner, GA_AttributeScope scope, const UT_StringHolder &name, int tuple_size, const GA_Defaults &defaults=GA_Defaults(0.0), const UT_Options *creation_args=0, const GA_AttributeOptions *attribute_options=0, GA_Storage storage=GA_STORE_REAL32, const GA_ReuseStrategy &reuse=GA_ReuseStrategy())
fpreal getTime() const
Definition: OP_Context.h:62
IMF_EXPORT IMATH_NAMESPACE::V3f direction(const IMATH_NAMESPACE::Box2i &dataWindow, const IMATH_NAMESPACE::V2f &pixelPosition)
GLsizei const GLchar *const * path
Definition: glcorearb.h:3341
UT_Vector3T< float > UT_Vector3
static PRM_SpareData * getGroupSelectButton(GA_GroupType group_type, const char *group_type_parm=NULL, int input_index=0, PRM_SpareData *merge_spare_data=NULL, const char *assoc_groups=NULL, GroupSelectAsOrdered ordered=GroupSelectAsOrdered::AUTO, const char *use_name_attr=nullptr, const char *select_script=nullptr)
GLboolean GLboolean g
Definition: glcorearb.h:1222
constexpr SYS_FORCE_INLINE T & z() noexcept
Definition: UT_Vector3.h:667
int64 exint
Definition: SYS_Types.h:125
UT_API UT_UndoManager * UTgetUndoManager()
virtual void forceRecook(bool evensmartcache=true)
PRM_API const PRM_Type PRM_ORD
int64 getMemoryUsage(bool inclusive=false) const
Definition: UT_Array.h:657
SYS_FORCE_INLINE const char * buffer() const
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1222
void addToMemoryUsage(int64 k)
Definition: UT_Undo.h:60
UT_ErrorSeverity
Definition: UT_Error.h:25
SOP_CustomBrush(OP_Network *net, const char *name, OP_Operator *op)
PRM_API PRM_Default PRMpointOneDefaults[]
bool addOperator(OP_Operator *op, std::ostream *err=nullptr)
SYS_FORCE_INLINE UT_Vector3 getPos3(GA_Offset ptoff) const
The ptoff passed is the point offset.
Definition: GA_Detail.h:185
PRM_API const PRM_Type PRM_XYZ_J
static PRM_ChoiceList pointGroupMenu
Definition: SOP_Node.h:1190
float fpreal32
Definition: SYS_Types.h:200
void addError(int code, const char *msg=0)
Definition: SOP_Node.h:1158
exint size() const
Definition: UT_Array.h:646
exint GA_Size
Defines the bit width for index and offset types in GA.
Definition: GA_Types.h:235
PRM_API const PRM_Type PRM_RGB_J
GA_RWHandleT< UT_Vector3F > GA_RWHandleV3
Definition: GA_Handle.h:1382
struct _cl_event * event
Definition: glcorearb.h:2961
bool load(UT_IStream &is, const char *extension, const char *path=0) override
GA_Size GA_Offset
Definition: GA_Types.h:641
bool load(UT_IStream &is, const char *extension, const char *path) override
OP_ERROR save(std::ostream &os, const OP_SaveFlags &flags, const char *path_prefix, const UT_String &name_override=UT_String()) override
GLdouble n
Definition: glcorearb.h:2008
GLfloat f
Definition: glcorearb.h:1926
void addToUndoBlock(UT_Undo *undo)
void updateData(exint numpts, UT_Array< SOP_CustomBrushData > &data)
OP_ERROR duplicateChangedSource(unsigned idx, OP_Context &ctx, int *changed=0, bool force=false)
Only duplicates the source if the source has changed since the last call to this method.
const GU_Detail * inputGeo(int index, OP_Context &)
Definition: SOP_Node.h:1147
OP_ERROR cookMySop(OP_Context &context) override
SOP_CustomBrushOperation
exint read(bool *array, exint sz=1)
Definition: UT_IStream.h:276
fpreal64 dot(const CE_VectorT< T > &a, const CE_VectorT< T > &b)
Definition: CE_Vector.h:130
SOP_NodeFlags mySopFlags
Definition: SOP_Node.h:1625
OP_ERROR cookInputGroups(OP_Context &context, int alone=0) override
OP_ERROR cookInputPointGroups(OP_Context &context, const GA_PointGroup *&group, bool alone=false, bool do_selection=true, int parm_index=0, int group_type_index=-1, bool allow_reference=true, bool ordered=false, bool detached=true, int input_index=0)
See cookInputPrimitiveGroups.
GLfloat GLfloat GLfloat alpha
Definition: glcorearb.h:112
GLuint const GLchar * name
Definition: glcorearb.h:786
PRM_API PRM_Name PRMgroupName
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1222
GA_Size GA_Index
Define the strictness of GA_Offset/GA_Index.
Definition: GA_Types.h:635
PRM_API const PRM_Type PRM_FLT_J
GLenum GLenum GLsizei void * table
Definition: glad.h:5129
void setManagesDataIDs(bool onOff)
Definition: SOP_NodeFlags.h:36
static OP_Node * myConstructor(OP_Network *, const char *, OP_Operator *)
SOP_UndoCustomBrushData(SOP_CustomBrush *sop, GA_Size oldnumpts, GA_Size numpts, UT_Array< SOP_CustomBrushData > &olddata, UT_Array< SOP_CustomBrushData > &data)
GLdouble t
Definition: glad.h:2397
int sprintf(const char *fmt,...) SYS_PRINTF_CHECK_ATTRIBUTE(2
GU_Detail * gdp
Definition: SOP_Node.h:1622
SYS_FORCE_INLINE GA_Index pointIndex(GA_Offset offset) const
Given a point's data offset, return its index.
Definition: GA_Detail.h:349
const GA_Attribute * findFloatTuple(GA_AttributeOwner owner, GA_AttributeScope scope, const UT_StringRef &name, int min_size=1, int max_size=-1) const
PRM_API PRM_Default PRMoneDefaults[]
#define GA_FOR_ALL_GROUP_PTOFF(gdp, grp, ptoff)
Definition: GA_GBMacros.h:96
GLuint color
Definition: glcorearb.h:1261
fpreal64 fpreal
Definition: SYS_Types.h:277
virtual int close(UT_IStream &is)
GLuint index
Definition: glcorearb.h:786
int willAcceptUndoAddition()
SYS_FORCE_INLINE const UT_String & getName() const
void newSopOperator(OP_OperatorTable *table)
static OP_Node * lookupNode(int unique_id, bool include_proxy=false)
Definition: OP_Node.h:696
SYS_FORCE_INLINE UT_StorageMathFloat_t< T > normalize() noexcept
Definition: UT_Vector3.h:376
void resetChangedSourceFlags()
GLboolean r
Definition: glcorearb.h:1222
SOP_CustomBrushEvent
constexpr SYS_FORCE_INLINE T & y() noexcept
Definition: UT_Vector3.h:665
static PRM_Template myTemplateList[]
SYS_FORCE_INLINE GA_Offset pointOffset(GA_Index index) const
Given a point's index (in append order), return its data offset.
Definition: GA_Detail.h:345
OP_ERROR save(std::ostream &os, const OP_SaveFlags &flags, const char *pathPrefix, const UT_String &name_override=UT_String()) override
Definition: format.h:895
SYS_FORCE_INLINE GA_Size getNumPoints() const
Return the number of points.
Definition: GA_Detail.h:334
constexpr SYS_FORCE_INLINE T & x() noexcept
Definition: UT_Vector3.h:663