HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
SOP_Star.C
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018
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  * The Star SOP
27  */
28 
29 #include "SOP_Star.h"
30 
31 // This is an automatically generated header file based on theDsFile, below,
32 // to provide SOP_StarParms, an easy way to access parameter values from
33 // SOP_StarVerb::cook with the correct type.
34 #include "SOP_Star.proto.h"
35 
36 #include <GU/GU_Detail.h>
37 #include <GEO/GEO_PrimPoly.h>
38 #include <OP/OP_Operator.h>
39 #include <OP/OP_OperatorTable.h>
40 #include <PRM/PRM_Include.h>
42 #include <UT/UT_DSOVersion.h>
43 #include <UT/UT_Interrupt.h>
44 #include <UT/UT_StringHolder.h>
45 #include <SYS/SYS_Math.h>
46 #include <limits.h>
47 
48 using namespace HDK_Sample;
49 
50 //
51 // Help is stored in a "wiki" style text file. This text file should be copied
52 // to $HOUDINI_PATH/help/nodes/sop/star.txt
53 //
54 // See the sample_install.sh file for an example.
55 //
56 
57 /// This is the internal name of the SOP type.
58 /// It isn't allowed to be the same as any other SOP's type name.
59 const UT_StringHolder SOP_Star::theSOPTypeName("hdk_star"_sh);
60 
61 /// newSopOperator is the hook that Houdini grabs from this dll
62 /// and invokes to register the SOP. In this case, we add ourselves
63 /// to the specified operator table.
64 void
66 {
67  table->addOperator(new OP_Operator(
68  SOP_Star::theSOPTypeName, // Internal name
69  "Star", // UI name
70  SOP_Star::myConstructor, // How to build the SOP
71  SOP_Star::buildTemplates(), // My parameters
72  0, // Min # of sources
73  0, // Max # of sources
74  nullptr, // Custom local variables (none)
75  OP_FLAG_GENERATOR)); // Flag it as generator
76 }
77 
78 /// This is a multi-line raw string specifying the parameter interface
79 /// for this SOP.
80 static const char *theDsFile = R"THEDSFILE(
81 {
82  name parameters
83  parm {
84  name "divs" // Internal parameter name
85  label "Divisions" // Descriptive parameter name for user interface
86  type integer
87  default { "5" } // Default for this parameter on new nodes
88  range { 2! 50 } // The value is prevented from going below 2 at all.
89  // The UI slider goes up to 50, but the value can go higher.
90  export all // This makes the parameter show up in the toolbox
91  // above the viewport when it's in the node's state.
92  }
93  parm {
94  name "rad"
95  label "Radius"
96  type vector2
97  size 2 // 2 components in a vector2
98  default { "1" "0.3" } // Outside and inside radius defaults
99  }
100  parm {
101  name "nradius"
102  label "Allow Negative Radius"
103  type toggle
104  default { "0" }
105  }
106  parm {
107  name "t"
108  label "Center"
109  type vector
110  size 3 // 3 components in a vector
111  default { "0" "0" "0" }
112  }
113  parm {
114  name "orient"
115  label "Orientation"
116  type ordinal
117  default { "0" } // Default to first entry in menu, "xy"
118  menu {
119  "xy" "XY Plane"
120  "yz" "YZ Plane"
121  "zx" "ZX Plane"
122  }
123  }
124 }
125 )THEDSFILE";
126 
129 {
130  static PRM_TemplateBuilder templ("SOP_Star.C"_sh, theDsFile);
131  return templ.templates();
132 }
133 
135 {
136 public:
138  virtual ~SOP_StarVerb() {}
139 
140  virtual SOP_NodeParms *allocParms() const { return new SOP_StarParms(); }
141  virtual UT_StringHolder name() const { return SOP_Star::theSOPTypeName; }
142 
143  virtual CookMode cookMode(const SOP_NodeParms *parms) const { return COOK_GENERIC; }
144 
145  virtual void cook(const CookParms &cookparms) const;
146 
147  /// This static data member automatically registers
148  /// this verb class at library load time.
150 };
151 
152 // The static member variable definition has to be outside the class definition.
153 // The declaration is inside the class.
155 
156 const SOP_NodeVerb *
158 {
159  return SOP_StarVerb::theVerb.get();
160 }
161 
162 /// This is the function that does the actual work.
163 void
165 {
166  auto &&sopparms = cookparms.parms<SOP_StarParms>();
167  GU_Detail *detail = cookparms.gdh().gdpNC();
168 
169  // We need two points per division
170  exint npoints = sopparms.getDivs()*2;
171 
172  if (npoints < 4)
173  {
174  // With the range restriction we have on the divisions, this
175  // is actually impossible, (except via integer overflow),
176  // but it shows how to add an error message or warning to the SOP.
177  cookparms.sopAddWarning(SOP_MESSAGE, "There must be at least 2 divisions; defaulting to 2.");
178  npoints = 4;
179  }
180 
181  // If this SOP has cooked before and it wasn't evicted from the cache,
182  // its output detail will contain the geometry from the last cook.
183  // If it hasn't cooked, or if it was evicted from the cache,
184  // the output detail will be empty.
185  // This knowledge can save us some effort, e.g. if the number of points on
186  // this cook is the same as on the last cook, we can just move the points,
187  // (i.e. modifying P), which can also save some effort for the viewport.
188 
189  GA_Offset start_ptoff;
190  if (detail->getNumPoints() != npoints)
191  {
192  // Either the SOP hasn't cooked, the detail was evicted from
193  // the cache, or the number of points changed since the last cook.
194 
195  // This destroys everything except the empty P and topology attributes.
196  detail->clearAndDestroy();
197 
198  // Build 1 closed polygon (as opposed to a curve),
199  // namely that has its closed flag set to true,
200  // and the right number of vertices, as a contiguous block
201  // of vertex offsets.
202  GA_Offset start_vtxoff;
203  detail->appendPrimitivesAndVertices(GA_PRIMPOLY, 1, npoints, start_vtxoff, true);
204 
205  // Create the right number of points, as a contiguous block
206  // of point offsets.
207  start_ptoff = detail->appendPointBlock(npoints);
208 
209  // Wire the vertices to the points.
210  for (exint i = 0; i < npoints; ++i)
211  {
212  detail->getTopology().wireVertexPoint(start_vtxoff+i,start_ptoff+i);
213  }
214 
215  // We added points, vertices, and primitives,
216  // so this will bump all topology attribute data IDs,
217  // P's data ID, and the primitive list data ID.
218  detail->bumpDataIdsForAddOrRemove(true, true, true);
219  }
220  else
221  {
222  // Same number of points as last cook, and we know that last time,
223  // we created a contiguous block of point offsets, so just get the
224  // first one.
225  start_ptoff = detail->pointOffset(GA_Index(0));
226 
227  // We'll only be modifying P, so we only need to bump P's data ID.
228  detail->getP()->bumpDataId();
229  }
230 
231  // Everything after this is just to figure out what to write to P and write it.
232 
233  const SOP_StarParms::Orient plane = sopparms.getOrient();
234  const bool allow_negative_radius = sopparms.getNradius();
235 
236  UT_Vector3 center = sopparms.getT();
237 
238  int xcoord, ycoord, zcoord;
239  switch (plane)
240  {
241  case SOP_StarParms::Orient::XY: // XY Plane
242  xcoord = 0;
243  ycoord = 1;
244  zcoord = 2;
245  break;
246  case SOP_StarParms::Orient::YZ: // YZ Plane
247  xcoord = 1;
248  ycoord = 2;
249  zcoord = 0;
250  break;
251  case SOP_StarParms::Orient::ZX: // XZ Plane
252  xcoord = 0;
253  ycoord = 2;
254  zcoord = 1;
255  break;
256  }
257 
258  // Start the interrupt scope
259  UT_AutoInterrupt boss("Building Star");
260  if (boss.wasInterrupted())
261  return;
262 
263  float tinc = M_PI*2 / (float)npoints;
264  float outer_radius = sopparms.getRad().x();
265  float inner_radius = sopparms.getRad().y();
266 
267  // Now, set all the points of the polygon
268  for (exint i = 0; i < npoints; i++)
269  {
270  // Check to see if the user has interrupted us...
271  if (boss.wasInterrupted())
272  break;
273 
274  float angle = (float)i * tinc;
275  bool odd = (i & 1);
276  float rad = odd ? inner_radius : outer_radius;
277  if (!allow_negative_radius && rad < 0)
278  rad = 0;
279 
280  UT_Vector3 pos(SYScos(angle)*rad, SYSsin(angle)*rad, 0);
281  // Put the circle in the correct plane.
282  pos = UT_Vector3(pos(xcoord), pos(ycoord), pos(zcoord));
283  // Move the circle to be centred at the correct position.
284  pos += center;
285 
286  // Since we created a contiguous block of point offsets,
287  // we can just add i to start_ptoff to find this point offset.
288  GA_Offset ptoff = start_ptoff + i;
289  detail->setPos3(ptoff, pos);
290  }
291 }
virtual CookMode cookMode(const SOP_NodeParms *parms) const
Definition: SOP_Star.C:143
void newSopOperator(OP_OperatorTable *table)
Definition: SOP_Star.C:65
UT_ErrorSeverity sopAddWarning(int code, const char *msg=0, const UT_SourceLocation *loc=0) const
Definition: SOP_NodeVerb.h:576
UT_Vector3T< float > UT_Vector3
#define OP_FLAG_GENERATOR
Definition: OP_Operator.h:67
virtual const SOP_NodeVerb * cookVerb() const override
Definition: SOP_Star.C:157
bool addOperator(OP_Operator *op, std::ostream *err=nullptr)
png_uint_32 i
Definition: png.h:2877
#define M_PI
Definition: ImathPlatform.h:51
static OP_Node * myConstructor(OP_Network *net, const char *name, OP_Operator *op)
Definition: SOP_Star.h:44
GA_Size GA_Offset
Definition: GA_Types.h:617
virtual UT_StringHolder name() const
Definition: SOP_Star.C:141
const T & parms() const
Definition: SOP_NodeVerb.h:543
virtual void cook(const CookParms &cookparms) const
This is the function that does the actual work.
Definition: SOP_Star.C:164
static const SOP_NodeVerb::Register< SOP_StarVerb > theVerb
Definition: SOP_Star.C:149
int64 exint
Definition: SYS_Types.h:109
T angle(const Vec2< T > &v1, const Vec2< T > &v2)
Definition: Vec2.h:480
GA_Size GA_Index
Define the strictness of GA_Offset/GA_Index.
Definition: GA_Types.h:611
GU_Detail * gdpNC()
static const UT_StringHolder theSOPTypeName
Definition: SOP_Star.h:49
virtual SOP_NodeParms * allocParms() const
Definition: SOP_Star.C:140
PRM_Template * templates()
static PRM_Template * buildTemplates()
Definition: SOP_Star.C:128
virtual ~SOP_StarVerb()
Definition: SOP_Star.C:138
GU_DetailHandle & gdh() const
The initial state of gdh depends on the cookMode()
Definition: SOP_NodeVerb.h:486